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