Statistics
| Branch: | Revision:

ffmpeg / libavformat / yuv4mpeg.c @ 2d745414

History | View | Annotate | Download (12 KB)

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

    
21
#define Y4M_MAGIC "YUV4MPEG2"
22
#define Y4M_FRAME_MAGIC "FRAME"
23
#define Y4M_LINE_MAX 256
24

    
25
#ifdef CONFIG_ENCODERS
26

    
27
static int yuv4_generate_header(AVFormatContext *s, char* buf)
28
{
29
    AVStream *st;
30
    int width, height;
31
    int raten, rated, aspectn, aspectd, n;
32
    char inter;
33
    char *colorspace = "";
34

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

    
39
    av_reduce(&raten, &rated, st->codec.frame_rate, st->codec.frame_rate_base, (1UL<<31)-1);
40
    
41
    aspectn = st->codec.sample_aspect_ratio.num;
42
    aspectd = st->codec.sample_aspect_ratio.den;
43
    
44
    if ( aspectn == 0 && aspectd == 1 ) aspectd = 0;  // 0:0 means unknown
45

    
46
    inter = 'p'; /* progressive is the default */
47
    if (st->codec.coded_frame && st->codec.coded_frame->interlaced_frame) {
48
        inter = st->codec.coded_frame->top_field_first ? 't' : 'b';
49
    }
50

    
51
    switch(st->codec.pix_fmt) {
52
    case PIX_FMT_YUV411P:
53
        colorspace = " C411 XYSCSS=411";
54
        break;
55
    case PIX_FMT_YUV420P:
56
        colorspace = (st->codec.codec_id == CODEC_ID_DVVIDEO)?" C420paldv XYSCSS=420PALDV":" C420mpeg2 XYSCSS=420MPEG2";
57
        break;
58
    case PIX_FMT_YUV422P:
59
        colorspace = " C422 XYSCSS=422";
60
        break;
61
    case PIX_FMT_YUV444P:
62
        colorspace = " C444 XYSCSS=444";
63
        break;
64
    }
65

    
66
    /* construct stream header, if this is the first frame */
67
    n = snprintf(buf, Y4M_LINE_MAX, "%s W%d H%d F%d:%d I%c A%d:%d%s\n",
68
                 Y4M_MAGIC,
69
                 width,
70
                 height,
71
                 raten, rated,
72
                 inter,
73
                 aspectn, aspectd,
74
                 colorspace);
75
                 
76
    return n;
77
}
78

    
79
static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
80
{
81
    AVStream *st = s->streams[pkt->stream_index];
82
    ByteIOContext *pb = &s->pb;
83
    AVPicture *picture;
84
    int* first_pkt = s->priv_data;
85
    int width, height, h_chroma_shift, v_chroma_shift;
86
    int i, m;
87
    char buf2[Y4M_LINE_MAX+1];
88
    char buf1[20];
89
    uint8_t *ptr, *ptr1, *ptr2;
90

    
91
    picture = (AVPicture *)pkt->data;
92

    
93
    /* for the first packet we have to output the header as well */
94
    if (*first_pkt) {
95
        *first_pkt = 0;
96
        if (yuv4_generate_header(s, buf2) < 0) {
97
            av_log(s, AV_LOG_ERROR, "Error. YUV4MPEG stream header write failed.\n");
98
            return AVERROR_IO;
99
        } else {
100
            put_buffer(pb, buf2, strlen(buf2)); 
101
        }
102
    }
103

    
104
    /* construct frame header */
105
    
106
    m = snprintf(buf1, sizeof(buf1), "%s\n", Y4M_FRAME_MAGIC);
107
    put_buffer(pb, buf1, strlen(buf1));
108

    
109
    width = st->codec.width;
110
    height = st->codec.height;
111
    
112
    ptr = picture->data[0];
113
    for(i=0;i<height;i++) {
114
        put_buffer(pb, ptr, width);
115
        ptr += picture->linesize[0];
116
    }
117

    
118
    // Adjust for smaller Cb and Cr planes
119
    avcodec_get_chroma_sub_sample(st->codec.pix_fmt, &h_chroma_shift, &v_chroma_shift);
120
    width >>= h_chroma_shift;
121
    height >>= v_chroma_shift;
122

    
123
    ptr1 = picture->data[1];
124
    ptr2 = picture->data[2];
125
    for(i=0;i<height;i++) {                /* Cb */
126
        put_buffer(pb, ptr1, width);
127
        ptr1 += picture->linesize[1];
128
    }
129
    for(i=0;i<height;i++) {        /* Cr */
130
        put_buffer(pb, ptr2, width);
131
            ptr2 += picture->linesize[2];
132
    }
133
    put_flush_packet(pb);
134
    return 0;
135
}
136

    
137
static int yuv4_write_header(AVFormatContext *s)
138
{
139
    int* first_pkt = s->priv_data;
140
    
141
    if (s->nb_streams != 1)
142
        return AVERROR_IO;
143
    
144
    if (s->streams[0]->codec.pix_fmt == PIX_FMT_YUV411P) {
145
        av_log(s, AV_LOG_ERROR, "Warning: generating rarely used 4:1:1 YUV stream, some mjpegtools might not work.\n");
146
    } 
147
    else if ((s->streams[0]->codec.pix_fmt != PIX_FMT_YUV420P) && 
148
             (s->streams[0]->codec.pix_fmt != PIX_FMT_YUV422P) && 
149
             (s->streams[0]->codec.pix_fmt != PIX_FMT_YUV444P)) {
150
        av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg only handles 4:4:4, 4:2:2, 4:2:0 and 4:1:1 planar YUV data. Use -pix_fmt to select one.\n");
151
        return AVERROR_IO;
152
    }
153
    
154
    *first_pkt = 1;
155
    return 0;
156
}
157

    
158
static int yuv4_write_trailer(AVFormatContext *s)
159
{
160
    return 0;
161
}
162

    
163
AVOutputFormat yuv4mpegpipe_oformat = {
164
    "yuv4mpegpipe",
165
    "YUV4MPEG pipe format",
166
    "",
167
    "yuv4mpeg",
168
    sizeof(int),
169
    CODEC_ID_NONE,
170
    CODEC_ID_RAWVIDEO,
171
    yuv4_write_header,
172
    yuv4_write_packet,
173
    yuv4_write_trailer,
174
    .flags = AVFMT_RAWPICTURE,
175
};
176
#endif //CONFIG_ENCODERS
177

    
178
/* Header size increased to allow room for optional flags */
179
#define MAX_YUV4_HEADER 80
180
#define MAX_FRAME_HEADER 80
181

    
182
static int yuv4_read_header(AVFormatContext *s, AVFormatParameters *ap)
183
{
184
    char header[MAX_YUV4_HEADER+10];  // Include headroom for the longest option
185
    char *tokstart,*tokend,*header_end;
186
    int i;
187
    ByteIOContext *pb = &s->pb;
188
    int width=-1, height=-1, raten=0, rated=0, aspectn=0, aspectd=0,interlaced_frame=0,top_field_first=0;
189
    enum PixelFormat pix_fmt=PIX_FMT_NB,alt_pix_fmt=PIX_FMT_NB;
190
    AVStream *st;
191
    
192
    for (i=0; i<MAX_YUV4_HEADER; i++) {
193
        header[i] = get_byte(pb);
194
        if (header[i] == '\n') {
195
            header[i+1] = 0x20;  // Add a space after last option. Makes parsing "444" vs "444alpha" easier.
196
            header[i+2] = 0;
197
            break;
198
        }
199
    }
200
    if (i == MAX_YUV4_HEADER) return -1;
201
    if (strncmp(header, Y4M_MAGIC, strlen(Y4M_MAGIC))) return -1;
202

    
203
    header_end = &header[i+1]; // Include space
204
    for(tokstart = &header[strlen(Y4M_MAGIC) + 1]; tokstart < header_end; tokstart++) {
205
        if (*tokstart==0x20) continue;
206
        switch (*tokstart++) {
207
        case 'W': // Width. Required.
208
            width = strtol(tokstart, &tokend, 10);
209
            tokstart=tokend;
210
            break;
211
        case 'H': // Height. Required.
212
            height = strtol(tokstart, &tokend, 10);
213
            tokstart=tokend;
214
            break;
215
        case 'C': // Color space
216
            if (strncmp("420jpeg",tokstart,7)==0)
217
                pix_fmt = PIX_FMT_YUV420P;
218
            else if (strncmp("420mpeg2",tokstart,8)==0)
219
                pix_fmt = PIX_FMT_YUV420P;
220
            else if (strncmp("420paldv", tokstart, 8)==0)
221
                pix_fmt = PIX_FMT_YUV420P;
222
            else if (strncmp("411", tokstart, 3)==0)
223
                pix_fmt = PIX_FMT_YUV411P;
224
            else if (strncmp("422", tokstart, 3)==0)
225
                pix_fmt = PIX_FMT_YUV422P;
226
            else if (strncmp("444alpha", tokstart, 8)==0) {
227
                av_log(s, AV_LOG_ERROR, "Cannot handle 4:4:4:4 YUV4MPEG stream.\n");
228
                return -1;
229
            } else if (strncmp("444", tokstart, 3)==0)
230
                pix_fmt = PIX_FMT_YUV444P;
231
            else if (strncmp("mono",tokstart, 4)==0) {
232
                av_log(s, AV_LOG_ERROR, "Cannot handle luma only YUV4MPEG stream.\n");
233
                return -1;
234
            } else {
235
                av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains an unknown pixel format.\n");
236
                return -1;
237
            }
238
            while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
239
            break;
240
        case 'I': // Interlace type
241
            switch (*tokstart++){
242
            case '?':
243
                break;
244
            case 'p':
245
                interlaced_frame=0;
246
                break;
247
            case 't':
248
                interlaced_frame=1;
249
                top_field_first=1;
250
                break;
251
            case 'b':
252
                interlaced_frame=1;
253
                top_field_first=0;
254
                break;
255
            case 'm':
256
                av_log(s, AV_LOG_ERROR, "YUV4MPEG stream contains mixed interlaced and non-interlaced frames.\n");
257
                return -1;
258
            default:
259
                av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
260
                return -1;
261
            }
262
            break;
263
        case 'F': // Frame rate
264
            sscanf(tokstart,"%d:%d",&raten,&rated); // 0:0 if unknown
265
            while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
266
            break;
267
        case 'A': // Pixel aspect
268
            sscanf(tokstart,"%d:%d",&aspectn,&aspectd); // 0:0 if unknown
269
            while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
270
            break;
271
        case 'X': // Vendor extensions
272
            if (strncmp("YSCSS=",tokstart,6)==0) {
273
                // Older nonstandard pixel format representation
274
                tokstart+=6;
275
                if (strncmp("420JPEG",tokstart,7)==0)
276
                    alt_pix_fmt=PIX_FMT_YUV420P;
277
                else if (strncmp("420MPEG2",tokstart,8)==0)
278
                    alt_pix_fmt=PIX_FMT_YUV420P;
279
                else if (strncmp("420PALDV",tokstart,8)==0)
280
                    alt_pix_fmt=PIX_FMT_YUV420P;
281
                else if (strncmp("411",tokstart,3)==0)
282
                    alt_pix_fmt=PIX_FMT_YUV411P;
283
                else if (strncmp("422",tokstart,3)==0)
284
                    alt_pix_fmt=PIX_FMT_YUV422P;
285
                else if (strncmp("444",tokstart,3)==0)
286
                    alt_pix_fmt=PIX_FMT_YUV444P;
287
            }
288
            while(tokstart<header_end&&*tokstart!=0x20) tokstart++;
289
            break;
290
        }
291
    }            
292

    
293
    if ((width == -1) || (height == -1)) {
294
        av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
295
        return -1;        
296
    }
297
    
298
    if (pix_fmt == PIX_FMT_NB) {
299
        if (alt_pix_fmt == PIX_FMT_NB)
300
            pix_fmt = PIX_FMT_YUV420P;
301
        else
302
            pix_fmt = alt_pix_fmt;
303
    }
304

    
305
    if (raten == 0 && rated == 0) {
306
        // Frame rate unknown
307
        raten = 25;
308
        rated = 1;
309
    }
310

    
311
    if (aspectn == 0 && aspectd == 0) {
312
        // Pixel aspect unknown
313
        aspectd = 1;
314
    }
315
        
316
    st = av_new_stream(s, 0);
317
    st = s->streams[0];
318
    st->codec.width = width;
319
    st->codec.height = height;
320
    av_reduce(&raten, &rated, raten, rated, (1UL<<31)-1);
321
    st->codec.frame_rate = raten;
322
    st->codec.frame_rate_base = rated;
323
    st->codec.pix_fmt = pix_fmt;
324
    st->codec.codec_type = CODEC_TYPE_VIDEO;
325
    st->codec.codec_id = CODEC_ID_RAWVIDEO;
326
    st->codec.sample_aspect_ratio= (AVRational){aspectn, aspectd};
327

    
328
    return 0;
329
}
330

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

    
338
    for (i=0; i<MAX_FRAME_HEADER; i++) {
339
        header[i] = get_byte(&s->pb);
340
        if (header[i] == '\n') {
341
            header[i+1] = 0;
342
            break;
343
        }
344
    }
345
    if (i == MAX_FRAME_HEADER) return -1;
346
    if (strncmp(header, Y4M_FRAME_MAGIC, strlen(Y4M_FRAME_MAGIC))) return -1;
347
    
348
    width = st->codec.width;
349
    height = st->codec.height;
350

    
351
    packet_size = avpicture_get_size(st->codec.pix_fmt, width, height);
352
    if (packet_size < 0)
353
        return -1;
354

    
355
    if (av_new_packet(pkt, packet_size) < 0)
356
        return AVERROR_IO;
357

    
358
    pkt->stream_index = 0;
359
    ret = get_buffer(&s->pb, pkt->data, pkt->size);
360
    if (ret != pkt->size) {
361
        av_free_packet(pkt);
362
        return AVERROR_IO;
363
    } else {
364
        return 0;
365
    }
366
}
367

    
368
static int yuv4_read_close(AVFormatContext *s)
369
{
370
    return 0;
371
}
372

    
373
AVInputFormat yuv4mpegpipe_iformat = {
374
    "yuv4mpegpipe",
375
    "YUV4MPEG pipe format",
376
    0,
377
    NULL,
378
    yuv4_read_header,
379
    yuv4_read_packet,
380
    yuv4_read_close,
381
    .extensions = "yuv4mpeg"
382
};
383

    
384
int yuv4mpeg_init(void)
385
{
386
    av_register_input_format(&yuv4mpegpipe_iformat);
387
#ifdef CONFIG_ENCODERS
388
    av_register_output_format(&yuv4mpegpipe_oformat);
389
#endif //CONFIG_ENCODERS
390
    return 0;
391
}
392