Statistics
| Branch: | Revision:

ffmpeg / libavformat / yuv4mpeg.c @ f96b17c5

History | View | Annotate | Download (12.1 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_GRAY8:
53
        colorspace = " Cmono";
54
        break;
55
    case PIX_FMT_YUV411P:
56
        colorspace = " C411 XYSCSS=411";
57
        break;
58
    case PIX_FMT_YUV420P:
59
        colorspace = (st->codec.codec_id == CODEC_ID_DVVIDEO)?" C420paldv XYSCSS=420PALDV":" C420mpeg2 XYSCSS=420MPEG2";
60
        break;
61
    case PIX_FMT_YUV422P:
62
        colorspace = " C422 XYSCSS=422";
63
        break;
64
    case PIX_FMT_YUV444P:
65
        colorspace = " C444 XYSCSS=444";
66
        break;
67
    }
68

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

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

    
94
    picture = (AVPicture *)pkt->data;
95

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

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

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

    
121
    if (st->codec.pix_fmt != PIX_FMT_GRAY8){
122
    // Adjust for smaller Cb and Cr planes
123
    avcodec_get_chroma_sub_sample(st->codec.pix_fmt, &h_chroma_shift, &v_chroma_shift);
124
    width >>= h_chroma_shift;
125
    height >>= v_chroma_shift;
126

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

    
142
static int yuv4_write_header(AVFormatContext *s)
143
{
144
    int* first_pkt = s->priv_data;
145
    
146
    if (s->nb_streams != 1)
147
        return AVERROR_IO;
148
    
149
    if (s->streams[0]->codec.pix_fmt == PIX_FMT_YUV411P) {
150
        av_log(s, AV_LOG_ERROR, "Warning: generating rarely used 4:1:1 YUV stream, some mjpegtools might not work.\n");
151
    } 
152
    else if ((s->streams[0]->codec.pix_fmt != PIX_FMT_YUV420P) && 
153
             (s->streams[0]->codec.pix_fmt != PIX_FMT_YUV422P) && 
154
             (s->streams[0]->codec.pix_fmt != PIX_FMT_GRAY8) && 
155
             (s->streams[0]->codec.pix_fmt != PIX_FMT_YUV444P)) {
156
        av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg only handles yuv444p, yuv422p, yuv420p, yuv411p and gray pixel formats. Use -pix_fmt to select one.\n");
157
        return AVERROR_IO;
158
    }
159
    
160
    *first_pkt = 1;
161
    return 0;
162
}
163

    
164
static int yuv4_write_trailer(AVFormatContext *s)
165
{
166
    return 0;
167
}
168

    
169
AVOutputFormat yuv4mpegpipe_oformat = {
170
    "yuv4mpegpipe",
171
    "YUV4MPEG pipe format",
172
    "",
173
    "yuv4mpeg",
174
    sizeof(int),
175
    CODEC_ID_NONE,
176
    CODEC_ID_RAWVIDEO,
177
    yuv4_write_header,
178
    yuv4_write_packet,
179
    yuv4_write_trailer,
180
    .flags = AVFMT_RAWPICTURE,
181
};
182
#endif //CONFIG_ENCODERS
183

    
184
/* Header size increased to allow room for optional flags */
185
#define MAX_YUV4_HEADER 80
186
#define MAX_FRAME_HEADER 80
187

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

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

    
298
    if ((width == -1) || (height == -1)) {
299
        av_log(s, AV_LOG_ERROR, "YUV4MPEG has invalid header.\n");
300
        return -1;        
301
    }
302
    
303
    if (pix_fmt == PIX_FMT_NB) {
304
        if (alt_pix_fmt == PIX_FMT_NB)
305
            pix_fmt = PIX_FMT_YUV420P;
306
        else
307
            pix_fmt = alt_pix_fmt;
308
    }
309

    
310
    if (raten == 0 && rated == 0) {
311
        // Frame rate unknown
312
        raten = 25;
313
        rated = 1;
314
    }
315

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

    
333
    return 0;
334
}
335

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

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

    
356
    packet_size = avpicture_get_size(st->codec.pix_fmt, width, height);
357
    if (packet_size < 0)
358
        return -1;
359

    
360
    if (av_new_packet(pkt, packet_size) < 0)
361
        return AVERROR_IO;
362

    
363
    pkt->stream_index = 0;
364
    ret = get_buffer(&s->pb, pkt->data, pkt->size);
365
    if (ret != pkt->size) {
366
        av_free_packet(pkt);
367
        return AVERROR_IO;
368
    } else {
369
        return 0;
370
    }
371
}
372

    
373
static int yuv4_read_close(AVFormatContext *s)
374
{
375
    return 0;
376
}
377

    
378
AVInputFormat yuv4mpegpipe_iformat = {
379
    "yuv4mpegpipe",
380
    "YUV4MPEG pipe format",
381
    0,
382
    NULL,
383
    yuv4_read_header,
384
    yuv4_read_packet,
385
    yuv4_read_close,
386
    .extensions = "yuv4mpeg"
387
};
388

    
389
int yuv4mpeg_init(void)
390
{
391
    av_register_input_format(&yuv4mpegpipe_iformat);
392
#ifdef CONFIG_ENCODERS
393
    av_register_output_format(&yuv4mpegpipe_oformat);
394
#endif //CONFIG_ENCODERS
395
    return 0;
396
}
397