]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/mpeg12enc.c
avutil/buffer: Switch AVBuffer API to size_t
[ffmpeg] / libavcodec / mpeg12enc.c
index d0b458e34bdb492992358d0b6465f885e08f556b..432d27e1f688d50abce908f1833336a6b45762e2 100644 (file)
 
 #include <stdint.h>
 
+#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 },
 };
 
@@ -1161,6 +1212,7 @@ 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,
 };
 
@@ -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 */