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