f5c85653dd42b75ff7057056112ea92c01d22aee
[ffmpeg.git] / libavformat / yuv4mpeg.c
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