yuv4mpeg.c 6.82 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * YUV4MPEG format
 * Copyright (c) 2001, 2002, 2003 Fabrice Bellard.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "avformat.h"

#define Y4M_MAGIC "YUV4MPEG2"
#define Y4M_FRAME_MAGIC "FRAME"
#define Y4M_LINE_MAX 256

25
#ifdef CONFIG_ENCODERS
26 27

static int yuv4_generate_header(AVFormatContext *s, char* buf)
28 29 30
{
    AVStream *st;
    int width, height;
Michael Niedermayer's avatar
Michael Niedermayer committed
31
    int raten, rated, aspectn, aspectd, n;
32
    char inter;
33 34 35 36

    st = s->streams[0];
    width = st->codec.width;
    height = st->codec.height;
37 38

    av_reduce(&raten, &rated, st->codec.frame_rate, st->codec.frame_rate_base, (1UL<<31)-1);
39
    
Michael Niedermayer's avatar
Michael Niedermayer committed
40 41
    aspectn = st->codec.sample_aspect_ratio.num;
    aspectd = st->codec.sample_aspect_ratio.den;
42
    
43 44
    inter = 'p'; /* progressive is the default */
    if (st->codec.coded_frame && st->codec.coded_frame->interlaced_frame) {
45
        inter = st->codec.coded_frame->top_field_first ? 't' : 'b';
46
    }
47 48

    /* construct stream header, if this is the first frame */
49
    n = snprintf(buf, Y4M_LINE_MAX, "%s W%d H%d F%d:%d I%c A%d:%d%s\n",
50 51 52 53
                 Y4M_MAGIC,
                 width,
                 height,
                 raten, rated,
54 55
                 inter,
                 aspectn, aspectd,
56
		 (st->codec.pix_fmt == PIX_FMT_YUV411P) ? " C411 XYSCSS=411" : " C420mpeg2 XYSCSS=420MPEG2");
57 58
		 
    return n;
59 60
}

61
static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
62
{
63
    AVStream *st = s->streams[pkt->stream_index];
64 65
    ByteIOContext *pb = &s->pb;
    AVPicture *picture;
66
    int* first_pkt = s->priv_data;
67 68
    int width, height;
    int i, m;
69
    char buf2[Y4M_LINE_MAX+1];
70
    char buf1[20];
71
    uint8_t *ptr, *ptr1, *ptr2;
72

73
    picture = (AVPicture *)pkt->data;
74

75 76 77 78
    /* for the first packet we have to output the header as well */
    if (*first_pkt) {
        *first_pkt = 0;
	if (yuv4_generate_header(s, buf2) < 0) {
79
	    av_log(s, AV_LOG_ERROR, "Error. YUV4MPEG stream header write failed.\n");
80
	    return AVERROR_IO;
81 82 83 84 85
	} else {
	    put_buffer(pb, buf2, strlen(buf2)); 
	}
    }

86
    /* construct frame header */
87
    
88
    m = snprintf(buf1, sizeof(buf1), "%s\n", Y4M_FRAME_MAGIC);
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
    put_buffer(pb, buf1, strlen(buf1));

    width = st->codec.width;
    height = st->codec.height;
    
    ptr = picture->data[0];
    for(i=0;i<height;i++) {
        put_buffer(pb, ptr, width);
        ptr += picture->linesize[0];
    }

    height >>= 1;
    width >>= 1;
    ptr1 = picture->data[1];
    ptr2 = picture->data[2];
    for(i=0;i<height;i++) {		/* Cb */
        put_buffer(pb, ptr1, width);
        ptr1 += picture->linesize[1];
    }
    for(i=0;i<height;i++) {	/* Cr */
        put_buffer(pb, ptr2, width);
            ptr2 += picture->linesize[2];
    }
    put_flush_packet(pb);
    return 0;
}

116 117 118 119 120
static int yuv4_write_header(AVFormatContext *s)
{
    int* first_pkt = s->priv_data;
    
    if (s->nb_streams != 1)
121
        return AVERROR_IO;
122 123
    
    if (s->streams[0]->codec.pix_fmt == PIX_FMT_YUV411P) {
124
        av_log(s, AV_LOG_ERROR, "Warning: generating non-standard 4:1:1 YUV stream, some mjpegtools might not work.\n");
125 126
    } 
    else if (s->streams[0]->codec.pix_fmt != PIX_FMT_YUV420P) {
127
        av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg only handles 4:2:0, 4:1:1 YUV data. Use -pix_fmt to select one.\n");
128
	return AVERROR_IO;
129 130 131 132 133 134
    }
    
    *first_pkt = 1;
    return 0;
}

135 136 137 138 139 140 141 142 143 144
static int yuv4_write_trailer(AVFormatContext *s)
{
    return 0;
}

AVOutputFormat yuv4mpegpipe_oformat = {
    "yuv4mpegpipe",
    "YUV4MPEG pipe format",
    "",
    "yuv4mpeg",
145
    sizeof(int),
146 147 148 149 150 151 152
    CODEC_ID_NONE,
    CODEC_ID_RAWVIDEO,
    yuv4_write_header,
    yuv4_write_packet,
    yuv4_write_trailer,
    .flags = AVFMT_RAWPICTURE,
};
153
#endif //CONFIG_ENCODERS
154

155 156
/* Header size increased to allow room for optional flags */
#define MAX_YUV4_HEADER 80
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
#define MAX_FRAME_HEADER 10

static int yuv4_read_header(AVFormatContext *s, AVFormatParameters *ap)
{
    char header[MAX_YUV4_HEADER+1];
    int i;
    ByteIOContext *pb = &s->pb;
    int width, height, raten, rated, aspectn, aspectd;
    char lacing;
    AVStream *st;
    
    for (i=0; i<MAX_YUV4_HEADER; i++) {
        header[i] = get_byte(pb);
	if (header[i] == '\n') {
	    header[i+1] = 0;
	    break;
	}
    }
    if (i == MAX_YUV4_HEADER) return -1;
    if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC))) return -1;
    sscanf(header+strlen(Y4M_MAGIC), " W%d H%d F%d:%d I%c A%d:%d",
           &width, &height, &raten, &rated, &lacing, &aspectn, &aspectd);
    
    st = av_new_stream(s, 0);
    st = s->streams[0];
    st->codec.width = width;
    st->codec.height = height;
    av_reduce(&raten, &rated, raten, rated, (1UL<<31)-1);
    st->codec.frame_rate = raten;
    st->codec.frame_rate_base = rated;
    st->codec.pix_fmt = PIX_FMT_YUV420P;
    st->codec.codec_type = CODEC_TYPE_VIDEO;
    st->codec.codec_id = CODEC_ID_RAWVIDEO;
Michael Niedermayer's avatar
Michael Niedermayer committed
190
    st->codec.sample_aspect_ratio= (AVRational){aspectn, aspectd};
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

    return 0;
}

static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    int i;
    char header[MAX_FRAME_HEADER+1];
    int packet_size, ret, width, height;
    AVStream *st = s->streams[0];

    for (i=0; i<MAX_FRAME_HEADER; i++) {
        header[i] = get_byte(&s->pb);
	if (header[i] == '\n') {
	    header[i+1] = 0;
	    break;
	}
    }
    if (i == MAX_FRAME_HEADER) return -1;
    if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC))) return -1;
    
    width = st->codec.width;
    height = st->codec.height;

    packet_size = avpicture_get_size(st->codec.pix_fmt, width, height);
    if (packet_size < 0)
217
        return -1;
218 219

    if (av_new_packet(pkt, packet_size) < 0)
220
        return AVERROR_IO;
221 222 223 224 225

    pkt->stream_index = 0;
    ret = get_buffer(&s->pb, pkt->data, pkt->size);
    if (ret != pkt->size) {
        av_free_packet(pkt);
226
        return AVERROR_IO;
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    } else {
        return 0;
    }
}

static int yuv4_read_close(AVFormatContext *s)
{
    return 0;
}

AVInputFormat yuv4mpegpipe_iformat = {
    "yuv4mpegpipe",
    "YUV4MPEG pipe format",
    0,
    NULL,
    yuv4_read_header,
    yuv4_read_packet,
    yuv4_read_close,
    .extensions = "yuv4mpeg"
};

int yuv4mpeg_init(void)
{
    av_register_input_format(&yuv4mpegpipe_iformat);
251
#ifdef CONFIG_ENCODERS
252
    av_register_output_format(&yuv4mpegpipe_oformat);
253
#endif //CONFIG_ENCODERS
254 255
    return 0;
}
256