X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fmpeg12enc.c;h=2fb2232f3c416e37525057471bfac205ebfb88de;hb=a247ac640df3da573cd661065bf53f37863e2b46;hp=d0b458e34bdb492992358d0b6465f885e08f556b;hpb=ff44c2d4f483cda53859ce019f3815c69239a7e0;p=ffmpeg diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c index d0b458e34bd..2fb2232f3c4 100644 --- a/libavcodec/mpeg12enc.c +++ b/libavcodec/mpeg12enc.c @@ -27,10 +27,12 @@ #include +#include "config.h" #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/log.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include "libavutil/timecode.h" #include "libavutil/stereo3d.h" @@ -41,7 +43,9 @@ #include "mpeg12data.h" #include "mpegutils.h" #include "mpegvideo.h" +#include "profiles.h" +#if CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER static const uint8_t svcd_scan_offset_placeholder[] = { 0x10, 0x0E, 0x00, 0x80, 0x81, 0x00, 0x80, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -58,10 +62,10 @@ static uint8_t uni_mpeg2_ac_vlc_len[64 * 64 * 2]; static uint32_t mpeg1_lum_dc_uni[512]; static uint32_t mpeg1_chr_dc_uni[512]; -static uint8_t mpeg1_index_run[2][64]; -static int8_t mpeg1_max_level[2][64]; +#define A53_MAX_CC_COUNT 0x1f +#endif /* CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER */ -static av_cold void init_uni_ac_vlc(RLTable *rl, uint8_t *uni_ac_vlc_len) +av_cold void ff_mpeg1_init_uni_ac_vlc(const RLTable *rl, uint8_t *uni_ac_vlc_len) { int i; @@ -96,6 +100,7 @@ static av_cold void init_uni_ac_vlc(RLTable *rl, uint8_t *uni_ac_vlc_len) } } +#if CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER static int find_frame_rate_index(MpegEncContext *s) { int i; @@ -137,43 +142,50 @@ static int find_frame_rate_index(MpegEncContext *s) static av_cold int encode_init(AVCodecContext *avctx) { + int ret; MpegEncContext *s = avctx->priv_data; + int max_size = avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ? 16383 : 4095; - if (ff_mpv_encode_init(avctx) < 0) - return -1; + if (avctx->width > max_size || avctx->height > max_size) { + av_log(avctx, AV_LOG_ERROR, "%s does not support resolutions above %dx%d\n", + CONFIG_SMALL ? avctx->codec->name : avctx->codec->long_name, + max_size, max_size); + return AVERROR(EINVAL); + } + if ((avctx->width & 0xFFF) == 0 && (avctx->height & 0xFFF) == 1) { + av_log(avctx, AV_LOG_ERROR, "Width / Height is invalid for MPEG2\n"); + return AVERROR(EINVAL); + } - if (find_frame_rate_index(s) < 0) { - if (s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(avctx, AV_LOG_ERROR, "MPEG-1/2 does not support %d/%d fps\n", - avctx->time_base.den, avctx->time_base.num); - return -1; - } else { - av_log(avctx, AV_LOG_INFO, - "MPEG-1/2 does not support %d/%d fps, there may be AV sync issues\n", - avctx->time_base.den, avctx->time_base.num); + if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { + if ((avctx->width & 0xFFF) == 0 || (avctx->height & 0xFFF) == 0) { + av_log(avctx, AV_LOG_ERROR, "Width or Height are not allowed to be multiples of 4096\n" + "add '-strict %d' if you want to use them anyway.\n", FF_COMPLIANCE_UNOFFICIAL); + return AVERROR(EINVAL); } } if (avctx->profile == FF_PROFILE_UNKNOWN) { if (avctx->level != FF_LEVEL_UNKNOWN) { av_log(avctx, AV_LOG_ERROR, "Set profile and level\n"); - return -1; + return AVERROR(EINVAL); } /* Main or 4:2:2 */ - avctx->profile = s->chroma_format == CHROMA_420 ? 4 : 0; + avctx->profile = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? FF_PROFILE_MPEG2_MAIN + : FF_PROFILE_MPEG2_422; } - if (avctx->level == FF_LEVEL_UNKNOWN) { - if (avctx->profile == 0) { /* 4:2:2 */ + if (avctx->profile == FF_PROFILE_MPEG2_422) { /* 4:2:2 */ if (avctx->width <= 720 && avctx->height <= 608) avctx->level = 5; /* Main */ else avctx->level = 2; /* High */ } else { - if (avctx->profile != 1 && s->chroma_format != CHROMA_420) { + if (avctx->profile != FF_PROFILE_MPEG2_HIGH && + avctx->pix_fmt != AV_PIX_FMT_YUV420P) { av_log(avctx, AV_LOG_ERROR, "Only High(1) and 4:2:2(0) profiles support 4:2:2 color sampling\n"); - return -1; + return AVERROR(EINVAL); } if (avctx->width <= 720 && avctx->height <= 576) avctx->level = 8; /* Main */ @@ -184,16 +196,18 @@ static av_cold int encode_init(AVCodecContext *avctx) } } - if ((avctx->width & 0xFFF) == 0 && (avctx->height & 0xFFF) == 1) { - av_log(avctx, AV_LOG_ERROR, "Width / Height is invalid for MPEG2\n"); - return AVERROR(EINVAL); - } + if ((ret = ff_mpv_encode_init(avctx)) < 0) + return ret; - if (s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { - if ((avctx->width & 0xFFF) == 0 || (avctx->height & 0xFFF) == 0) { - av_log(avctx, AV_LOG_ERROR, "Width or Height are not allowed to be multiples of 4096\n" - "add '-strict %d' if you want to use them anyway.\n", FF_COMPLIANCE_UNOFFICIAL); + if (find_frame_rate_index(s) < 0) { + if (s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(avctx, AV_LOG_ERROR, "MPEG-1/2 does not support %d/%d fps\n", + avctx->time_base.den, avctx->time_base.num); return AVERROR(EINVAL); + } else { + av_log(avctx, AV_LOG_INFO, + "MPEG-1/2 does not support %d/%d fps, there may be AV sync issues\n", + avctx->time_base.den, avctx->time_base.num); } } @@ -203,16 +217,9 @@ static av_cold int encode_init(AVCodecContext *avctx) if (s->drop_frame_timecode && s->frame_rate_index != 4) { av_log(avctx, AV_LOG_ERROR, "Drop frame time code only allowed with 1001/30000 fps\n"); - return -1; + return AVERROR(EINVAL); } -#if FF_API_PRIVATE_OPT -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->timecode_frame_start) - s->timecode_frame_start = avctx->timecode_frame_start; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (s->tc_opt_str) { AVRational rate = ff_mpeg12_frame_rate_tab[s->frame_rate_index]; int ret = av_timecode_init_from_string(&s->tc, rate, s->tc_opt_str, s); @@ -229,7 +236,7 @@ FF_ENABLE_DEPRECATION_WARNINGS static void put_header(MpegEncContext *s, int header) { - avpriv_align_put_bits(&s->pb); + align_put_bits(&s->pb); put_bits(&s->pb, 16, header >> 16); put_sbits(&s->pb, 16, header); } @@ -319,7 +326,7 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) put_header(s, EXT_START_CODE); put_bits(&s->pb, 4, 1); // seq ext - put_bits(&s->pb, 1, s->avctx->profile == 0); // escx 1 for 4:2:2 profile + put_bits(&s->pb, 1, s->avctx->profile == FF_PROFILE_MPEG2_422); // escx 1 for 4:2:2 profile put_bits(&s->pb, 3, s->avctx->profile); // profile put_bits(&s->pb, 4, s->avctx->level); // level @@ -433,7 +440,7 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s, int picture_number) (s->picture_number - s->gop_picture_number) & 0x3ff); put_bits(&s->pb, 3, s->pict_type); - s->vbv_delay_ptr = s->pb.buf + put_bits_count(&s->pb) / 8; + s->vbv_delay_ptr = s->pb.buf + put_bytes_count(&s->pb, 0); put_bits(&s->pb, 16, 0xFFFF); /* vbv_delay */ // RAL: Forward f_code also needed for B-frames @@ -544,6 +551,36 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s, int picture_number) } } + if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->a53_cc) { + side_data = av_frame_get_side_data(s->current_picture_ptr->f, + AV_FRAME_DATA_A53_CC); + if (side_data) { + if (side_data->size <= A53_MAX_CC_COUNT * 3 && side_data->size % 3 == 0) { + int i = 0; + + put_header (s, USER_START_CODE); + + put_bits(&s->pb, 8, 'G'); // user_identifier + put_bits(&s->pb, 8, 'A'); + put_bits(&s->pb, 8, '9'); + put_bits(&s->pb, 8, '4'); + put_bits(&s->pb, 8, 3); // user_data_type_code + put_bits(&s->pb, 8, + (side_data->size / 3 & A53_MAX_CC_COUNT) | 0x40); // flags, cc_count + put_bits(&s->pb, 8, 0xff); // em_data + + for (i = 0; i < side_data->size; i++) + put_bits(&s->pb, 8, side_data->data[i]); + + put_bits(&s->pb, 8, 0xff); // marker_bits + } else { + av_log(s->avctx, AV_LOG_WARNING, + "Closed Caption size (%"SIZE_SPECIFIER") can not exceed " + "93 bytes and must be a multiple of 3\n", side_data->size); + } + } + } + s->mb_y = 0; ff_mpeg1_encode_slice_header(s); } @@ -683,8 +720,8 @@ next_coef: MASK_ABS(sign, alevel); sign &= 1; - if (alevel <= mpeg1_max_level[0][run]) { - code = mpeg1_index_run[0][run] + alevel - 1; + if (alevel <= ff_rl_mpeg1.max_level[0][run]) { + code = ff_rl_mpeg1.index_run[0][run] + alevel - 1; /* store the VLC & sign at once */ put_bits(&s->pb, table_vlc[code][1] + 1, (table_vlc[code][0] << 1) + sign); @@ -1000,84 +1037,77 @@ void ff_mpeg1_encode_mb(MpegEncContext *s, int16_t block[8][64], mpeg1_encode_mb_internal(s, block, motion_x, motion_y, 8); } -av_cold void ff_mpeg1_encode_init(MpegEncContext *s) +static av_cold void mpeg12_encode_init_static(void) { - static int done = 0; + static uint8_t mpeg12_static_rl_table_store[2][2][2*MAX_RUN + MAX_LEVEL + 3]; - ff_mpeg12_common_init(s); + ff_rl_init(&ff_rl_mpeg1, mpeg12_static_rl_table_store[0]); + ff_rl_init(&ff_rl_mpeg2, mpeg12_static_rl_table_store[1]); - if (!done) { - int f_code; - int mv; - int i; + ff_mpeg1_init_uni_ac_vlc(&ff_rl_mpeg1, uni_mpeg1_ac_vlc_len); + ff_mpeg1_init_uni_ac_vlc(&ff_rl_mpeg2, uni_mpeg2_ac_vlc_len); - done = 1; - ff_rl_init(&ff_rl_mpeg1, ff_mpeg12_static_rl_table_store[0]); - ff_rl_init(&ff_rl_mpeg2, ff_mpeg12_static_rl_table_store[1]); + /* build unified dc encoding tables */ + for (int i = -255; i < 256; i++) { + int adiff, index; + int bits, code; + int diff = i; - for (i = 0; i < 64; i++) { - mpeg1_max_level[0][i] = ff_rl_mpeg1.max_level[0][i]; - mpeg1_index_run[0][i] = ff_rl_mpeg1.index_run[0][i]; - } + adiff = FFABS(diff); + if (diff < 0) + diff--; + index = av_log2(2 * adiff); - init_uni_ac_vlc(&ff_rl_mpeg1, uni_mpeg1_ac_vlc_len); - if (s->intra_vlc_format) - init_uni_ac_vlc(&ff_rl_mpeg2, uni_mpeg2_ac_vlc_len); - - /* build unified dc encoding tables */ - for (i = -255; i < 256; i++) { - int adiff, index; - int bits, code; - int diff = i; - - adiff = FFABS(diff); - if (diff < 0) - diff--; - index = av_log2(2 * adiff); - - bits = ff_mpeg12_vlc_dc_lum_bits[index] + index; - code = (ff_mpeg12_vlc_dc_lum_code[index] << index) + - av_mod_uintp2(diff, index); - mpeg1_lum_dc_uni[i + 255] = bits + (code << 8); - - bits = ff_mpeg12_vlc_dc_chroma_bits[index] + index; - code = (ff_mpeg12_vlc_dc_chroma_code[index] << index) + - av_mod_uintp2(diff, index); - mpeg1_chr_dc_uni[i + 255] = bits + (code << 8); - } + bits = ff_mpeg12_vlc_dc_lum_bits[index] + index; + code = (ff_mpeg12_vlc_dc_lum_code[index] << index) + + av_mod_uintp2(diff, index); + mpeg1_lum_dc_uni[i + 255] = bits + (code << 8); - for (f_code = 1; f_code <= MAX_FCODE; f_code++) - for (mv = -MAX_DMV; mv <= MAX_DMV; mv++) { - int len; + bits = ff_mpeg12_vlc_dc_chroma_bits[index] + index; + code = (ff_mpeg12_vlc_dc_chroma_code[index] << index) + + av_mod_uintp2(diff, index); + mpeg1_chr_dc_uni[i + 255] = bits + (code << 8); + } - if (mv == 0) { - len = ff_mpeg12_mbMotionVectorTable[0][1]; - } else { - int val, bit_size, code; - - bit_size = f_code - 1; - - val = mv; - if (val < 0) - val = -val; - val--; - code = (val >> bit_size) + 1; - if (code < 17) - len = ff_mpeg12_mbMotionVectorTable[code][1] + - 1 + bit_size; - else - len = ff_mpeg12_mbMotionVectorTable[16][1] + - 2 + bit_size; - } + for (int f_code = 1; f_code <= MAX_FCODE; f_code++) + for (int mv = -MAX_DMV; mv <= MAX_DMV; mv++) { + int len; - mv_penalty[f_code][mv + MAX_DMV] = len; + if (mv == 0) { + len = ff_mpeg12_mbMotionVectorTable[0][1]; + } else { + int val, bit_size, code; + + bit_size = f_code - 1; + + val = mv; + if (val < 0) + val = -val; + val--; + code = (val >> bit_size) + 1; + if (code < 17) + len = ff_mpeg12_mbMotionVectorTable[code][1] + + 1 + bit_size; + else + len = ff_mpeg12_mbMotionVectorTable[16][1] + + 2 + bit_size; } + mv_penalty[f_code][mv + MAX_DMV] = len; + } + + + for (int f_code = MAX_FCODE; f_code > 0; f_code--) + for (int mv = -(8 << f_code); mv < (8 << f_code); mv++) + fcode_tab[mv + MAX_MV] = f_code; +} + +av_cold void ff_mpeg1_encode_init(MpegEncContext *s) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + + ff_mpeg12_common_init(s); - for (f_code = MAX_FCODE; f_code > 0; f_code--) - for (mv = -(8 << f_code); mv < (8 << f_code); mv++) - fcode_tab[mv + MAX_MV] = f_code; - } s->me.mv_penalty = mv_penalty; s->fcode_tab = fcode_tab; if (s->codec_id == AV_CODEC_ID_MPEG1VIDEO) { @@ -1096,32 +1126,41 @@ av_cold void ff_mpeg1_encode_init(MpegEncContext *s) } s->inter_ac_vlc_length = s->inter_ac_vlc_last_length = uni_mpeg1_ac_vlc_len; + + ff_thread_once(&init_static_once, mpeg12_encode_init_static); } #define OFFSET(x) offsetof(MpegEncContext, x) #define VE AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM #define COMMON_OPTS \ { "gop_timecode", "MPEG GOP Timecode in hh:mm:ss[:;.]ff format. Overrides timecode_frame_start.", \ - OFFSET(tc_opt_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, VE },\ - { "intra_vlc", "Use MPEG-2 intra VLC table.", \ - OFFSET(intra_vlc_format), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \ + OFFSET(tc_opt_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE },\ { "drop_frame_timecode", "Timecode is in drop frame format.", \ OFFSET(drop_frame_timecode), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \ { "scan_offset", "Reserve space for SVCD scan offset user data.", \ OFFSET(scan_offset), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \ { "timecode_frame_start", "GOP timecode frame start number, in non-drop-frame format", \ OFFSET(timecode_frame_start), AV_OPT_TYPE_INT64, {.i64 = -1 }, -1, INT64_MAX, VE}, \ + FF_MPV_COMMON_BFRAME_OPTS static const AVOption mpeg1_options[] = { COMMON_OPTS FF_MPV_COMMON_OPTS +#if FF_API_MPEGVIDEO_OPTS + FF_MPV_DEPRECATED_MPEG_QUANT_OPT + FF_MPV_DEPRECATED_A53_CC_OPT + FF_MPV_DEPRECATED_MATRIX_OPT +#endif { NULL }, }; static const AVOption mpeg2_options[] = { COMMON_OPTS + { "intra_vlc", "Use MPEG-2 intra VLC table.", + OFFSET(intra_vlc_format), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "non_linear_quant", "Use nonlinear quantizer.", OFFSET(q_scale_type), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "alternate_scan", "Enable alternate scantable.", OFFSET(alternate_scan), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { "seq_disp_ext", "Write sequence_display_extension blocks.", OFFSET(seq_disp_ext), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE, "seq_disp_ext" }, { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, VE, "seq_disp_ext" }, { "never", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, VE, "seq_disp_ext" }, @@ -1133,7 +1172,19 @@ static const AVOption mpeg2_options[] = { { "secam", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_SECAM }, 0, 0, VE, "video_format" }, { "mac", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_MAC }, 0, 0, VE, "video_format" }, { "unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_UNSPECIFIED}, 0, 0, VE, "video_format" }, +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, { .i64 = value }, 0, 0, VE, "avctx.level" + { LEVEL("high", 4) }, + { LEVEL("high1440", 6) }, + { LEVEL("main", 8) }, + { LEVEL("low", 10) }, +#undef LEVEL FF_MPV_COMMON_OPTS +#if FF_API_MPEGVIDEO_OPTS + { "mpeg_quant", "Deprecated, does nothing", OFFSET(mpeg_quant), + AV_OPT_TYPE_INT, {.i64 = 1 }, 0, 1, VE | AV_OPT_FLAG_DEPRECATED }, + FF_MPV_DEPRECATED_MATRIX_OPT +#endif + FF_MPEG2_PROFILE_OPTS { NULL }, }; @@ -1148,7 +1199,7 @@ static const AVClass mpeg ## x ## _class = { \ mpeg12_class(1) mpeg12_class(2) -AVCodec ff_mpeg1video_encoder = { +const AVCodec ff_mpeg1video_encoder = { .name = "mpeg1video", .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video"), .type = AVMEDIA_TYPE_VIDEO, @@ -1161,10 +1212,11 @@ AVCodec ff_mpeg1video_encoder = { .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .priv_class = &mpeg1_class, }; -AVCodec ff_mpeg2video_encoder = { +const AVCodec ff_mpeg2video_encoder = { .name = "mpeg2video", .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 video"), .type = AVMEDIA_TYPE_VIDEO, @@ -1178,5 +1230,7 @@ AVCodec ff_mpeg2video_encoder = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE }, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .priv_class = &mpeg2_class, }; +#endif /* CONFIG_MPEG1VIDEO_ENCODER || CONFIG_MPEG2VIDEO_ENCODER */