1/*
2 * YUV4MPEG muxer
3 * Copyright (c) 2001, 2002, 2003 Fabrice Bellard
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "libavutil/pixdesc.h"
23#include "avformat.h"
24#include "internal.h"
25#include "yuv4mpeg.h"
26
27#define Y4M_LINE_MAX 256
28
29static int yuv4_generate_header(AVFormatContext *s, char* buf)
30{
31    AVStream *st;
32    int width, height;
33    int raten, rated, aspectn, aspectd, n;
34    char inter;
35    const char *colorspace = "";
36
37    st     = s->streams[0];
38    width  = st->codec->width;
39    height = st->codec->height;
40
41    // TODO: should be avg_frame_rate
42    av_reduce(&raten, &rated, st->time_base.den,
43              st->time_base.num, (1UL << 31) - 1);
44
45    aspectn = st->sample_aspect_ratio.num;
46    aspectd = st->sample_aspect_ratio.den;
47
48    if (aspectn == 0 && aspectd == 1)
49        aspectd = 0;  // 0:0 means unknown
50
51    switch (st->codec->field_order) {
52    case AV_FIELD_TB:
53    case AV_FIELD_TT: inter = 't'; break;
54    case AV_FIELD_BT:
55    case AV_FIELD_BB: inter = 'b'; break;
56    default:          inter = 'p'; break;
57    }
58
59    switch (st->codec->pix_fmt) {
60    case AV_PIX_FMT_GRAY8:
61        colorspace = " Cmono";
62        break;
63    case AV_PIX_FMT_GRAY16:
64        colorspace = " Cmono16";
65        break;
66    case AV_PIX_FMT_YUV411P:
67        colorspace = " C411 XYSCSS=411";
68        break;
69    case AV_PIX_FMT_YUV420P:
70        switch (st->codec->chroma_sample_location) {
71        case AVCHROMA_LOC_TOPLEFT: colorspace = " C420paldv XYSCSS=420PALDV"; break;
72        case AVCHROMA_LOC_LEFT:    colorspace = " C420mpeg2 XYSCSS=420MPEG2"; break;
73        default:                   colorspace = " C420jpeg XYSCSS=420JPEG";   break;
74        }
75        break;
76    case AV_PIX_FMT_YUV422P:
77        colorspace = " C422 XYSCSS=422";
78        break;
79    case AV_PIX_FMT_YUV444P:
80        colorspace = " C444 XYSCSS=444";
81        break;
82    case AV_PIX_FMT_YUV420P9:
83        colorspace = " C420p9 XYSCSS=420P9";
84        break;
85    case AV_PIX_FMT_YUV422P9:
86        colorspace = " C422p9 XYSCSS=422P9";
87        break;
88    case AV_PIX_FMT_YUV444P9:
89        colorspace = " C444p9 XYSCSS=444P9";
90        break;
91    case AV_PIX_FMT_YUV420P10:
92        colorspace = " C420p10 XYSCSS=420P10";
93        break;
94    case AV_PIX_FMT_YUV422P10:
95        colorspace = " C422p10 XYSCSS=422P10";
96        break;
97    case AV_PIX_FMT_YUV444P10:
98        colorspace = " C444p10 XYSCSS=444P10";
99        break;
100    case AV_PIX_FMT_YUV420P12:
101        colorspace = " C420p12 XYSCSS=420P12";
102        break;
103    case AV_PIX_FMT_YUV422P12:
104        colorspace = " C422p12 XYSCSS=422P12";
105        break;
106    case AV_PIX_FMT_YUV444P12:
107        colorspace = " C444p12 XYSCSS=444P12";
108        break;
109    case AV_PIX_FMT_YUV420P14:
110        colorspace = " C420p14 XYSCSS=420P14";
111        break;
112    case AV_PIX_FMT_YUV422P14:
113        colorspace = " C422p14 XYSCSS=422P14";
114        break;
115    case AV_PIX_FMT_YUV444P14:
116        colorspace = " C444p14 XYSCSS=444P14";
117        break;
118    case AV_PIX_FMT_YUV420P16:
119        colorspace = " C420p16 XYSCSS=420P16";
120        break;
121    case AV_PIX_FMT_YUV422P16:
122        colorspace = " C422p16 XYSCSS=422P16";
123        break;
124    case AV_PIX_FMT_YUV444P16:
125        colorspace = " C444p16 XYSCSS=444P16";
126        break;
127    }
128
129    /* construct stream header, if this is the first frame */
130    n = snprintf(buf, Y4M_LINE_MAX, "%s W%d H%d F%d:%d I%c A%d:%d%s\n",
131                 Y4M_MAGIC, width, height, raten, rated, inter,
132                 aspectn, aspectd, colorspace);
133
134    return n;
135}
136
137static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
138{
139    AVStream *st = s->streams[pkt->stream_index];
140    AVIOContext *pb = s->pb;
141    AVPicture *picture, picture_tmp;
142    int* first_pkt = s->priv_data;
143    int width, height, h_chroma_shift, v_chroma_shift;
144    int i;
145    char buf2[Y4M_LINE_MAX + 1];
146    char buf1[20];
147    uint8_t *ptr, *ptr1, *ptr2;
148
149    memcpy(&picture_tmp, pkt->data, sizeof(AVPicture));
150    picture = &picture_tmp;
151
152    /* for the first packet we have to output the header as well */
153    if (*first_pkt) {
154        *first_pkt = 0;
155        if (yuv4_generate_header(s, buf2) < 0) {
156            av_log(s, AV_LOG_ERROR,
157                   "Error. YUV4MPEG stream header write failed.\n");
158            return AVERROR(EIO);
159        } else {
160            avio_write(pb, buf2, strlen(buf2));
161        }
162    }
163
164    /* construct frame header */
165
166    snprintf(buf1, sizeof(buf1), "%s\n", Y4M_FRAME_MAGIC);
167    avio_write(pb, buf1, strlen(buf1));
168
169    width  = st->codec->width;
170    height = st->codec->height;
171
172    ptr = picture->data[0];
173
174    switch (st->codec->pix_fmt) {
175    case AV_PIX_FMT_GRAY8:
176    case AV_PIX_FMT_YUV411P:
177    case AV_PIX_FMT_YUV420P:
178    case AV_PIX_FMT_YUV422P:
179    case AV_PIX_FMT_YUV444P:
180        break;
181    case AV_PIX_FMT_GRAY16:
182    case AV_PIX_FMT_YUV420P9:
183    case AV_PIX_FMT_YUV422P9:
184    case AV_PIX_FMT_YUV444P9:
185    case AV_PIX_FMT_YUV420P10:
186    case AV_PIX_FMT_YUV422P10:
187    case AV_PIX_FMT_YUV444P10:
188    case AV_PIX_FMT_YUV420P12:
189    case AV_PIX_FMT_YUV422P12:
190    case AV_PIX_FMT_YUV444P12:
191    case AV_PIX_FMT_YUV420P14:
192    case AV_PIX_FMT_YUV422P14:
193    case AV_PIX_FMT_YUV444P14:
194    case AV_PIX_FMT_YUV420P16:
195    case AV_PIX_FMT_YUV422P16:
196    case AV_PIX_FMT_YUV444P16:
197        width *= 2;
198        break;
199    default:
200        av_log(s, AV_LOG_ERROR, "The pixel format '%s' is not supported.\n",
201               av_get_pix_fmt_name(st->codec->pix_fmt));
202        return AVERROR(EINVAL);
203    }
204
205    for (i = 0; i < height; i++) {
206        avio_write(pb, ptr, width);
207        ptr += picture->linesize[0];
208    }
209
210    if (st->codec->pix_fmt != AV_PIX_FMT_GRAY8 &&
211        st->codec->pix_fmt != AV_PIX_FMT_GRAY16) {
212        // Adjust for smaller Cb and Cr planes
213        av_pix_fmt_get_chroma_sub_sample(st->codec->pix_fmt, &h_chroma_shift,
214                                         &v_chroma_shift);
215        width  = FF_CEIL_RSHIFT(width,  h_chroma_shift);
216        height = FF_CEIL_RSHIFT(height, v_chroma_shift);
217
218        ptr1 = picture->data[1];
219        ptr2 = picture->data[2];
220        for (i = 0; i < height; i++) {     /* Cb */
221            avio_write(pb, ptr1, width);
222            ptr1 += picture->linesize[1];
223        }
224        for (i = 0; i < height; i++) {     /* Cr */
225            avio_write(pb, ptr2, width);
226            ptr2 += picture->linesize[2];
227        }
228    }
229
230    return 0;
231}
232
233static int yuv4_write_header(AVFormatContext *s)
234{
235    int *first_pkt = s->priv_data;
236
237    if (s->nb_streams != 1)
238        return AVERROR(EIO);
239
240    if (s->streams[0]->codec->codec_id != AV_CODEC_ID_RAWVIDEO) {
241        av_log(s, AV_LOG_ERROR, "ERROR: Only rawvideo supported.\n");
242        return AVERROR_INVALIDDATA;
243    }
244
245    switch (s->streams[0]->codec->pix_fmt) {
246    case AV_PIX_FMT_YUV411P:
247        av_log(s, AV_LOG_WARNING, "Warning: generating rarely used 4:1:1 YUV "
248               "stream, some mjpegtools might not work.\n");
249        break;
250    case AV_PIX_FMT_GRAY8:
251    case AV_PIX_FMT_GRAY16:
252    case AV_PIX_FMT_YUV420P:
253    case AV_PIX_FMT_YUV422P:
254    case AV_PIX_FMT_YUV444P:
255        break;
256    case AV_PIX_FMT_YUV420P9:
257    case AV_PIX_FMT_YUV422P9:
258    case AV_PIX_FMT_YUV444P9:
259    case AV_PIX_FMT_YUV420P10:
260    case AV_PIX_FMT_YUV422P10:
261    case AV_PIX_FMT_YUV444P10:
262    case AV_PIX_FMT_YUV420P12:
263    case AV_PIX_FMT_YUV422P12:
264    case AV_PIX_FMT_YUV444P12:
265    case AV_PIX_FMT_YUV420P14:
266    case AV_PIX_FMT_YUV422P14:
267    case AV_PIX_FMT_YUV444P14:
268    case AV_PIX_FMT_YUV420P16:
269    case AV_PIX_FMT_YUV422P16:
270    case AV_PIX_FMT_YUV444P16:
271        if (s->streams[0]->codec->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
272            av_log(s, AV_LOG_ERROR, "'%s' is not a official yuv4mpegpipe pixel format. "
273                   "Use '-strict -1' to encode to this pixel format.\n",
274                   av_get_pix_fmt_name(s->streams[0]->codec->pix_fmt));
275            return AVERROR(EINVAL);
276        }
277        av_log(s, AV_LOG_WARNING, "Warning: generating non standard YUV stream. "
278               "Mjpegtools will not work.\n");
279        break;
280    default:
281        av_log(s, AV_LOG_ERROR, "ERROR: yuv4mpeg can only handle "
282               "yuv444p, yuv422p, yuv420p, yuv411p and gray8 pixel formats. "
283               "And using 'strict -1' also yuv444p9, yuv422p9, yuv420p9, "
284               "yuv444p10, yuv422p10, yuv420p10, "
285               "yuv444p12, yuv422p12, yuv420p12, "
286               "yuv444p14, yuv422p14, yuv420p14, "
287               "yuv444p16, yuv422p16, yuv420p16 "
288               "and gray16 pixel formats. "
289               "Use -pix_fmt to select one.\n");
290        return AVERROR(EIO);
291    }
292
293    *first_pkt = 1;
294    return 0;
295}
296
297AVOutputFormat ff_yuv4mpegpipe_muxer = {
298    .name              = "yuv4mpegpipe",
299    .long_name         = NULL_IF_CONFIG_SMALL("YUV4MPEG pipe"),
300    .extensions        = "y4m",
301    .priv_data_size    = sizeof(int),
302    .audio_codec       = AV_CODEC_ID_NONE,
303    .video_codec       = AV_CODEC_ID_RAWVIDEO,
304    .write_header      = yuv4_write_header,
305    .write_packet      = yuv4_write_packet,
306    .flags             = AVFMT_RAWPICTURE,
307};
308