[FFmpeg-devel] [PATCH v2 10/10] vtenc: Fixed mixed declarations and code.

kernrj at gmail.com kernrj at gmail.com
Wed Nov 18 19:49:58 CET 2015


From: Rick Kern <kernrj at gmail.com>

Moved all declarations to the top of their block.

Signed-off-by: Rick Kern <kernrj at gmail.com>
---
 libavcodec/vtenc.c | 409 ++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 260 insertions(+), 149 deletions(-)

diff --git a/libavcodec/vtenc.c b/libavcodec/vtenc.c
index 78a918b..a8cc340 100644
--- a/libavcodec/vtenc.c
+++ b/libavcodec/vtenc.c
@@ -67,17 +67,18 @@ typedef struct VTEncContext{
 } VTEncContext;
 
 static void set_async_error(VTEncContext* vtctx, int err){
+    BufNode* info;
+
     pthread_mutex_lock(&vtctx->lock);
 
     vtctx->async_error = err;
 
-    BufNode* info = vtctx->q_head;
+    info = vtctx->q_head;
     vtctx->q_head = vtctx->q_tail = NULL;
 
     while(info){
-        CFRelease(info->cm_buffer);
-
         BufNode* next = info->next;
+        CFRelease(info->cm_buffer);
         free(info);
         info = next;
     }
@@ -86,6 +87,8 @@ static void set_async_error(VTEncContext* vtctx, int err){
 }
 
 static int vtenc_q_pop(VTEncContext* vtctx, bool wait, CMSampleBufferRef* buf){
+    BufNode* info;
+
     pthread_mutex_lock(&vtctx->lock);
 
     if(vtctx->async_error){
@@ -110,7 +113,7 @@ static int vtenc_q_pop(VTEncContext* vtctx, bool wait, CMSampleBufferRef* buf){
         return 0;
     }
 
-    BufNode* info = vtctx->q_head;
+    info = vtctx->q_head;
     vtctx->q_head = vtctx->q_head->next;
     if(!vtctx->q_head){
         vtctx->q_tail = NULL;
@@ -141,12 +144,12 @@ static void vtenc_q_push(VTEncContext* vtctx, CMSampleBufferRef buffer){
     pthread_cond_signal(&vtctx->cv_sample_sent);
 
     if(!vtctx->q_head){
-        vtctx->q_head = vtctx->q_tail = info;
-        pthread_mutex_unlock(&vtctx->lock);
-        return;
+        vtctx->q_head = info;
+    }
+    else{
+        vtctx->q_tail->next = info;
     }
 
-    vtctx->q_tail->next = info;
     vtctx->q_tail = info;
 
     pthread_mutex_unlock(&vtctx->lock);
@@ -172,22 +175,21 @@ static void vtenc_free_block(void* opaque, uint8_t* data){
  *            In all cases, *dst_size is set to the number of bytes used starting
  *            at *dst.
  */
-
-static int get_params_info(
+static int get_params_size(
     AVCodecContext* avctx,
     CMVideoFormatDescriptionRef vid_fmt,
     size_t* size)
 {
     size_t total_size = 0;
     size_t ps_count;
-
+    size_t i;
     OSStatus status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, 0, NULL, NULL, &ps_count, NULL);
     if(status){
         av_log(avctx, AV_LOG_ERROR, "Error getting parameter set count: %d\n", status);
         return AVERROR_EXTERNAL;
     }
 
-    for(size_t i = 0; i < ps_count; i++){
+    for(i = 0; i < ps_count; i++){
         const uint8_t* ps;
         size_t ps_size;
         status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, i, &ps, &ps_size, NULL, NULL);
@@ -211,22 +213,26 @@ static int copy_param_sets(
 {
     size_t ps_count;
     OSStatus status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, 0, NULL, NULL, &ps_count, NULL);
+    size_t offset = 0;
+    size_t i;
+
     if(status){
         av_log(avctx, AV_LOG_ERROR, "Error getting parameter set count for copying: %d\n", status);
         return AVERROR_EXTERNAL;
     }
 
-    size_t offset = 0;
-    for(size_t i = 0; i < ps_count; i++){
+    for(i = 0; i < ps_count; i++){
         const uint8_t* ps;
         size_t ps_size;
+        size_t next_offset;
+
         status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, i, &ps, &ps_size, NULL, NULL);
         if(status){
             av_log(avctx, AV_LOG_ERROR, "Error getting parameter set data for index %zd: %d\n", i, status);
             return AVERROR_EXTERNAL;
         }
 
-        size_t next_offset = offset + sizeof(start_code) + ps_size;
+        next_offset = offset + sizeof(start_code) + ps_size;
         if(dst_size < next_offset){
             av_log(avctx, AV_LOG_ERROR, "Error: buffer too small for parameter sets.\n");
             return AVERROR_BUFFER_TOO_SMALL;
@@ -244,15 +250,16 @@ static int copy_param_sets(
 
 static int set_extradata(AVCodecContext* avctx, CMSampleBufferRef sample_buffer){
     CMVideoFormatDescriptionRef vid_fmt;
+    size_t total_size;
+    int status;
+
     vid_fmt = CMSampleBufferGetFormatDescription(sample_buffer);
     if(!vid_fmt){
         av_log(avctx, AV_LOG_ERROR, "No video format.\n");
         return AVERROR_EXTERNAL;
     }
 
-    size_t total_size;
-    int status;
-    status = get_params_info(avctx, vid_fmt, &total_size);
+    status = get_params_size(avctx, vid_fmt, &total_size);
     if(status){
         av_log(avctx, AV_LOG_ERROR, "Could not get parameter sets.\n");
         return status;
@@ -280,9 +287,8 @@ static av_cold void vtenc_output_callback(
     VTEncodeInfoFlags flags,
     CM_NULLABLE CMSampleBufferRef sample_buffer)
 {
-    av_assert0(ctx);
     AVCodecContext* avctx = (AVCodecContext*)ctx;
-    VTEncContext*   vtctx = (VTEncContext*)avctx->priv_data;
+    VTEncContext*   vtctx = avctx->priv_data;
 
     if(vtctx->async_error){
         if(sample_buffer) CFRelease(sample_buffer);
@@ -312,14 +318,16 @@ static int get_length_code_size(
     size_t* size)
 {
     CMVideoFormatDescriptionRef vid_fmt;
+    int isize;
+    OSStatus status;
+
     vid_fmt = CMSampleBufferGetFormatDescription(sample_buffer);
     if(!vid_fmt){
         av_log(avctx, AV_LOG_ERROR, "Error getting buffer format description.\n");
         return AVERROR_EXTERNAL;
     }
 
-    int isize;
-    OSStatus status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, 0, NULL, NULL, NULL, &isize);
+    status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, 0, NULL, NULL, NULL, &isize);
     if(status){
         av_log(avctx, AV_LOG_ERROR, "Error getting length code size: %d\n", status);
         return AVERROR_EXTERNAL;
@@ -329,8 +337,46 @@ static int get_length_code_size(
     return 0;
 }
 
+typedef enum VTEncLevel{
+    kLevel_Auto,
+    kLevel_1_3,
+    kLevel_3_0,
+    kLevel_3_1,
+    kLevel_3_2,
+    kLevel_4_0,
+    kLevel_4_1,
+    kLevel_4_2,
+    kLevel_5_0,
+    kLevel_5_1,
+    kLevel_5_2,
+} VTEncLevel;
+
+typedef struct VTEncValuePair{
+    const char *const str;
+    const VTEncLevel value;
+} VTEncValuePair;
+
+//Missing level aren't supported by VideoToolbox.
+static const VTEncValuePair vtenc_h264_level_pairs[] = {
+    { "auto", kLevel_Auto },
+    { "1.3" , kLevel_1_3 },
+    { "3"   , kLevel_3_0 },
+    { "3.0" , kLevel_3_0 },
+    { "3.1" , kLevel_3_1 },
+    { "3.2" , kLevel_3_2 },
+    { "4"   , kLevel_4_0 },
+    { "4.0" , kLevel_4_0 },
+    { "4.1" , kLevel_4_1 },
+    { "4.2" , kLevel_4_2 },
+    { "5"   , kLevel_5_0 },
+    { "5.0" , kLevel_5_0 },
+    { "5.1" , kLevel_5_1 },
+    { "5.2" , kLevel_5_2 },
+    { NULL }
+};
+
 static bool get_h264_profile(AVCodecContext* avctx, int* profile_num){
-    VTEncContext* vtctx = (VTEncContext*)avctx->priv_data;
+    VTEncContext* vtctx = avctx->priv_data;
 
     const char* profile = vtctx->profile;
     if(!profile){
@@ -353,80 +399,69 @@ static bool get_h264_profile(AVCodecContext* avctx, int* profile_num){
     return true;
 }
 
-static bool get_h264_level(AVCodecContext* avctx, int* level_num){
-    VTEncContext* vtctx = (VTEncContext*)avctx->priv_data;
+static bool get_h264_level(AVCodecContext* avctx, VTEncLevel* level_num){
+    VTEncContext* vtctx = avctx->priv_data;
+    int i;
 
     if(!vtctx->level){
-        *level_num = FF_LEVEL_UNKNOWN;
+        *level_num = kLevel_Auto;
         return true;
     }
 
-    char* end;
-    unsigned long major = strtoul(vtctx->level, &end, 10);
-    unsigned long minor = 0;
-
-    if(!major || (*end && *end != '.')){
-        av_log(avctx, AV_LOG_ERROR, "Error parsing level '%s'\n", vtctx->level);
-        return false;
-    }
-
-    if(*end){
-        minor = strtoul(end + 1, &end, 10);
-    }
-
-    if(*end){
-        av_log(avctx, AV_LOG_ERROR, "Error parsing level '%s'\n", vtctx->level);
-        return false;
+    for(i = 0; vtenc_h264_level_pairs[i].str; i++){
+        const VTEncValuePair* pair = &vtenc_h264_level_pairs[i];
+        if(!strcmp(pair->str, vtctx->level)){
+            *level_num = pair->value;
+            return true;
+        }
     }
 
-    *level_num = (int)(major * 10 + minor);
-    return true;
+    return false;
 }
 
 /*
  * Returns true on success.
  *
- * If profileLevelVal is NULL and this method returns true, don't specify the
+ * If profile_level_val is NULL and this method returns true, don't specify the
  * profile/level to the encoder.
  */
-static bool getVTProfileLevel(AVCodecContext* avctx, CFStringRef* profileLevelVal){
-    VTEncContext* vtctx = (VTEncContext*)avctx->priv_data;
-
+static bool get_vt_profile_level(AVCodecContext* avctx, CFStringRef* profile_level_val){
+    VTEncContext* vtctx = avctx->priv_data;
     int profile;
-    int level;
+    VTEncLevel level;
 
     if(!get_h264_profile(avctx, &profile)){
-        return AVERROR(EINVAL);
+        return false;
     }
 
     if(!get_h264_level(avctx, &level)){
-        return AVERROR(EINVAL);
+        return false;
     }
 
     if(profile == FF_LEVEL_UNKNOWN &&
-       level   != FF_LEVEL_UNKNOWN)
+       level   != kLevel_Auto)
     {
         profile = vtctx->has_b_frames ? FF_PROFILE_H264_MAIN : FF_PROFILE_H264_BASELINE;
     }
 
     switch(profile){
         case FF_PROFILE_UNKNOWN:
-            *profileLevelVal = NULL;
+            *profile_level_val = NULL;
             return true;
 
         case FF_PROFILE_H264_BASELINE:
             switch(level){
-                case FF_LEVEL_UNKNOWN: *profileLevelVal = kVTProfileLevel_H264_Baseline_AutoLevel; break;
-                case 13: *profileLevelVal = kVTProfileLevel_H264_Baseline_1_3; break;
-                case 30: *profileLevelVal = kVTProfileLevel_H264_Baseline_3_0; break;
-                case 31: *profileLevelVal = kVTProfileLevel_H264_Baseline_3_1; break;
-                case 32: *profileLevelVal = kVTProfileLevel_H264_Baseline_3_2; break;
-                case 40: *profileLevelVal = kVTProfileLevel_H264_Baseline_4_0; break;
-                case 41: *profileLevelVal = kVTProfileLevel_H264_Baseline_4_1; break;
-                case 42: *profileLevelVal = kVTProfileLevel_H264_Baseline_4_2; break;
-                case 50: *profileLevelVal = kVTProfileLevel_H264_Baseline_5_0; break;
-                case 51: *profileLevelVal = kVTProfileLevel_H264_Baseline_5_1; break;
-                case 52: *profileLevelVal = kVTProfileLevel_H264_Baseline_5_2; break;
+                case kLevel_Auto: *profile_level_val = kVTProfileLevel_H264_Baseline_AutoLevel; break;
+                case kLevel_1_3: *profile_level_val = kVTProfileLevel_H264_Baseline_1_3; break;
+                case kLevel_3_0: *profile_level_val = kVTProfileLevel_H264_Baseline_3_0; break;
+                case kLevel_3_1: *profile_level_val = kVTProfileLevel_H264_Baseline_3_1; break;
+                case kLevel_3_2: *profile_level_val = kVTProfileLevel_H264_Baseline_3_2; break;
+                case kLevel_4_0: *profile_level_val = kVTProfileLevel_H264_Baseline_4_0; break;
+                case kLevel_4_1: *profile_level_val = kVTProfileLevel_H264_Baseline_4_1; break;
+                case kLevel_4_2: *profile_level_val = kVTProfileLevel_H264_Baseline_4_2; break;
+                case kLevel_5_0: *profile_level_val = kVTProfileLevel_H264_Baseline_5_0; break;
+                case kLevel_5_1: *profile_level_val = kVTProfileLevel_H264_Baseline_5_1; break;
+                case kLevel_5_2: *profile_level_val = kVTProfileLevel_H264_Baseline_5_2; break;
                 default:
                     av_log(avctx, AV_LOG_ERROR, "Unrecognized level %s (%d)\n", vtctx->level, level);
                     return false;
@@ -435,16 +470,16 @@ static bool getVTProfileLevel(AVCodecContext* avctx, CFStringRef* profileLevelVa
 
         case FF_PROFILE_H264_MAIN:
             switch(level){
-                case FF_LEVEL_UNKNOWN: *profileLevelVal = kVTProfileLevel_H264_Main_AutoLevel; break;
-                case 30: *profileLevelVal = kVTProfileLevel_H264_Main_3_0; break;
-                case 31: *profileLevelVal = kVTProfileLevel_H264_Main_3_1; break;
-                case 32: *profileLevelVal = kVTProfileLevel_H264_Main_3_2; break;
-                case 40: *profileLevelVal = kVTProfileLevel_H264_Main_4_0; break;
-                case 41: *profileLevelVal = kVTProfileLevel_H264_Main_4_1; break;
-                case 42: *profileLevelVal = kVTProfileLevel_H264_Main_4_2; break;
-                case 50: *profileLevelVal = kVTProfileLevel_H264_Main_5_0; break;
-                case 51: *profileLevelVal = kVTProfileLevel_H264_Main_5_1; break;
-                case 52: *profileLevelVal = kVTProfileLevel_H264_Main_5_2; break;
+                case kLevel_Auto: *profile_level_val = kVTProfileLevel_H264_Main_AutoLevel; break;
+                case kLevel_3_0: *profile_level_val = kVTProfileLevel_H264_Main_3_0; break;
+                case kLevel_3_1: *profile_level_val = kVTProfileLevel_H264_Main_3_1; break;
+                case kLevel_3_2: *profile_level_val = kVTProfileLevel_H264_Main_3_2; break;
+                case kLevel_4_0: *profile_level_val = kVTProfileLevel_H264_Main_4_0; break;
+                case kLevel_4_1: *profile_level_val = kVTProfileLevel_H264_Main_4_1; break;
+                case kLevel_4_2: *profile_level_val = kVTProfileLevel_H264_Main_4_2; break;
+                case kLevel_5_0: *profile_level_val = kVTProfileLevel_H264_Main_5_0; break;
+                case kLevel_5_1: *profile_level_val = kVTProfileLevel_H264_Main_5_1; break;
+                case kLevel_5_2: *profile_level_val = kVTProfileLevel_H264_Main_5_2; break;
                 default:
                     av_log(avctx, AV_LOG_ERROR, "Unrecognized level %s (%d)\n", vtctx->level, level);
                     return false;
@@ -453,16 +488,16 @@ static bool getVTProfileLevel(AVCodecContext* avctx, CFStringRef* profileLevelVa
 
         case FF_PROFILE_H264_HIGH:
             switch(level){
-                case FF_LEVEL_UNKNOWN:  *profileLevelVal = kVTProfileLevel_H264_High_AutoLevel; break;
-                case 30: *profileLevelVal = kVTProfileLevel_H264_High_3_0; break;
-                case 31: *profileLevelVal = kVTProfileLevel_H264_High_3_1; break;
-                case 32: *profileLevelVal = kVTProfileLevel_H264_High_3_2; break;
-                case 40: *profileLevelVal = kVTProfileLevel_H264_High_4_0; break;
-                case 41: *profileLevelVal = kVTProfileLevel_H264_High_4_1; break;
-                case 42: *profileLevelVal = kVTProfileLevel_H264_High_4_2; break;
-                case 50: *profileLevelVal = kVTProfileLevel_H264_High_5_0; break;
-                case 51: *profileLevelVal = kVTProfileLevel_H264_High_5_1; break;
-                case 52: *profileLevelVal = kVTProfileLevel_H264_High_5_2; break;
+                case kLevel_Auto:  *profile_level_val = kVTProfileLevel_H264_High_AutoLevel; break;
+                case kLevel_3_0: *profile_level_val = kVTProfileLevel_H264_High_3_0; break;
+                case kLevel_3_1: *profile_level_val = kVTProfileLevel_H264_High_3_1; break;
+                case kLevel_3_2: *profile_level_val = kVTProfileLevel_H264_High_3_2; break;
+                case kLevel_4_0: *profile_level_val = kVTProfileLevel_H264_High_4_0; break;
+                case kLevel_4_1: *profile_level_val = kVTProfileLevel_H264_High_4_1; break;
+                case kLevel_4_2: *profile_level_val = kVTProfileLevel_H264_High_4_2; break;
+                case kLevel_5_0: *profile_level_val = kVTProfileLevel_H264_High_5_0; break;
+                case kLevel_5_1: *profile_level_val = kVTProfileLevel_H264_High_5_1; break;
+                case kLevel_5_2: *profile_level_val = kVTProfileLevel_H264_High_5_2; break;
                 default:
                     av_log(avctx, AV_LOG_ERROR, "Unrecognized level %s (%d)\n", vtctx->level, level);
                     return false;
@@ -476,9 +511,13 @@ static bool getVTProfileLevel(AVCodecContext* avctx, CFStringRef* profileLevelVa
 }
 
 static av_cold int vtenc_init(AVCodecContext* avctx){
-    VTEncContext* vtctx = (VTEncContext*)avctx->priv_data;
-    CMVideoCodecType codec_type;
-    OSStatus status;
+    CFMutableDictionaryRef enc_info;
+    CMVideoCodecType       codec_type;
+    VTEncContext*          vtctx = avctx->priv_data;
+    CFStringRef            profile_level;
+    SInt32                 bit_rate = avctx->bit_rate;
+    CFNumberRef            bit_rate_num;
+    int                    status;
 
     codec_type = get_cm_codec_type(avctx->codec_id);
     if(!codec_type){
@@ -488,14 +527,13 @@ static av_cold int vtenc_init(AVCodecContext* avctx){
 
     vtctx->has_b_frames = avctx->has_b_frames && avctx->max_b_frames > 0;
 
-    CFStringRef profileLevel;
-    if(!getVTProfileLevel(avctx, &profileLevel)){
+    if(!get_vt_profile_level(avctx, &profile_level)){
         return AVERROR(EINVAL);
     }
 
     vtctx->session = NULL;
 
-    CFMutableDictionaryRef enc_info = CFDictionaryCreateMutable(
+    enc_info = CFDictionaryCreateMutable(
         kCFAllocatorDefault,
         20,
         &kCFCopyStringDictionaryKeyCallBacks,
@@ -541,13 +579,14 @@ static av_cold int vtenc_init(AVCodecContext* avctx){
     }
 #endif
 
+    CFRelease(enc_info);
+
     if(status || !vtctx->session){
         av_log(avctx, AV_LOG_ERROR, "Error: cannot create compression session: %d\n", status);
         return AVERROR_EXTERNAL;
     }
 
-    SInt32 bit_rate = avctx->bit_rate;
-    CFNumberRef bit_rate_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &bit_rate);
+    bit_rate_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &bit_rate);
     if(!bit_rate_num) return AVERROR(ENOMEM);
 
     status = VTSessionSetProperty(vtctx->session, kVTCompressionPropertyKey_AverageBitRate, bit_rate_num);
@@ -558,8 +597,8 @@ static av_cold int vtenc_init(AVCodecContext* avctx){
         return AVERROR_EXTERNAL;
     }
 
-    if(profileLevel){
-        status = VTSessionSetProperty(vtctx->session, kVTCompressionPropertyKey_ProfileLevel, profileLevel);
+    if(profile_level){
+        status = VTSessionSetProperty(vtctx->session, kVTCompressionPropertyKey_ProfileLevel, profile_level);
 
         if(status){
             av_log(avctx, AV_LOG_ERROR, "Error setting profile/level property: %d\n", status);
@@ -603,17 +642,18 @@ static void vtenc_get_frame_info(
         CMSampleBufferRef buffer,
         bool* is_key_frame)
 {
-    CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(buffer, false);
-    CFIndex len = !attachments ? 0 : CFArrayGetCount(attachments);
+    CFArrayRef      attachments = CMSampleBufferGetSampleAttachmentsArray(buffer, false);
+    CFDictionaryRef attachment;
+    CFBooleanRef    not_sync;
+    CFIndex         len = !attachments ? 0 : CFArrayGetCount(attachments);
 
     if(!len){
         *is_key_frame = true;
         return;
     }
 
-    CFDictionaryRef attachment = (CFDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
+    attachment = (CFDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
 
-    CFBooleanRef not_sync;
     if(CFDictionaryGetValueIfPresent(attachment, kCMSampleAttachmentKey_NotSync, (const void**)&not_sync)){
         *is_key_frame = !CFBooleanGetValue(not_sync);
     }
@@ -622,22 +662,40 @@ static void vtenc_get_frame_info(
     }
 }
 
+/**
+ * Replaces length codes with H.264 Annex B start codes.
+ * length_code_size must equal sizeof(start_code).
+ * On failure, the contents of data may have been modified.
+ *
+ * @param length_code_size Byte length of each length code
+ * @param data Call with NAL units prefixed with length codes.
+ *             On success, the length codes are replace with
+ *             start codes.
+ * @param size Length of data, excluding any padding.
+ * @return 0 on success
+ *         AVERROR_BUFFER_TOO_SMALL if length code size is smaller
+ *         than a start code or if a length_code in data specifies
+ *         data beyond the end of its buffer.
+ */
 static int replace_length_codes(size_t length_code_size, uint8_t* data, size_t size){
+    size_t remaining_size = size;
+
     if(length_code_size != sizeof(start_code)){
-        av_log(NULL, AV_LOG_ERROR, "lc != sizeof\n");
+        av_log(NULL, AV_LOG_ERROR, "Start code size and length code size not equal.\n");
         return AVERROR_BUFFER_TOO_SMALL;
     }
 
-    size_t remaining_size = size;
     while(remaining_size > 0){
         size_t box_len = 0;
-        for(size_t i = 0; i < length_code_size; i++){
+        size_t i;
+
+        for(i = 0; i < length_code_size; i++){
             box_len <<= 8;
             box_len |= data[i];
         }
 
         if(remaining_size < box_len + sizeof(start_code)){
-            av_log(NULL, AV_LOG_ERROR, "too small 2\n");
+            av_log(NULL, AV_LOG_ERROR, "Length is out of range.\n");
             AVERROR_BUFFER_TOO_SMALL;
         }
 
@@ -649,7 +707,25 @@ static int replace_length_codes(size_t length_code_size, uint8_t* data, size_t s
     return 0;
 }
 
-//expects zeroed memory
+/**
+ * Copies NAL units and replaces length codes with
+ * H.264 Annex B start codes. On failure, the contents of
+ * dst_data may have been modified.
+ *
+ * @param length_code_size Byte length of each length code
+ * @param src_data NAL units prefixed with length codes.
+ * @param src_size Length of buffer, excluding any padding.
+ * @param dst_data Must be zeroed before calling this function.
+ *                 Contains the copied NAL units prefixed with
+ *                 start codes when the function returns
+ *                 successfully.
+ * @param dst_size Length of dst_data
+ * @return 0 on success
+ *         AVERROR_INVALIDDATA if length_code_size is invalid
+ *         AVERROR_BUFFER_TOO_SMALL if dst_data is too small
+ *         or if a length_code in src_data specifies data beyond
+ *         the end of its buffer.
+ */
 static int copy_replace_length_codes(
     size_t length_code_size,
     const uint8_t* src_data,
@@ -657,21 +733,29 @@ static int copy_replace_length_codes(
     uint8_t* dst_data,
     size_t dst_size)
 {
+    size_t remaining_src_size = src_size;
+    size_t remaining_dst_size = dst_size;
+
     if(length_code_size > 4){
         return AVERROR_INVALIDDATA;
     }
 
-    size_t remaining_src_size = src_size;
-    size_t remaining_dst_size = dst_size;
     while(remaining_src_size > 0){
+        size_t curr_src_len;
+        size_t curr_dst_len;
         size_t box_len = 0;
-        for(size_t i = 0; i < length_code_size; i++){
+        size_t i;
+
+        uint8_t*       dst_box;
+        const uint8_t* src_box;
+
+        for(i = 0; i < length_code_size; i++){
             box_len <<= 8;
             box_len |= src_data[i];
         }
 
-        size_t curr_src_len = box_len + length_code_size;
-        size_t curr_dst_len = box_len + sizeof(start_code);
+        curr_src_len = box_len + length_code_size;
+        curr_dst_len = box_len + sizeof(start_code);
 
         if(remaining_src_size < curr_src_len){
             return AVERROR_BUFFER_TOO_SMALL;
@@ -681,8 +765,8 @@ static int copy_replace_length_codes(
             return AVERROR_BUFFER_TOO_SMALL;
         }
 
-        uint8_t*       dst_box = dst_data + sizeof(start_code);
-        const uint8_t* src_box = src_data + length_code_size;
+        dst_box = dst_data + sizeof(start_code);
+        src_box = src_data + length_code_size;
 
         memcpy(dst_data, start_code, sizeof(start_code));
         memcpy(dst_box,  src_box,    box_len);
@@ -702,12 +786,23 @@ static int vtenc_cm_to_avpacket(
     CMSampleBufferRef sample_buffer,
     AVPacket* pkt)
 {
-    VTEncContext* vtctx = (VTEncContext*)avctx->priv_data;
+    VTEncContext* vtctx = avctx->priv_data;
+
+    int     status;
+    bool    is_key_frame;
+    bool    add_header;
+    char*   buf_data;
+    size_t  length_code_size;
+    size_t  header_size = 0;
+    size_t  in_buf_size;
+    int64_t dts_delta;
+    int64_t time_base_num;
+    CMTime  pts;
+    CMTime  dts;
+
+    CMBlockBufferRef            block;
+    CMVideoFormatDescriptionRef vid_fmt;
 
-    bool is_key_frame;
-    bool add_header;
-    size_t length_code_size;
-    int status;
 
     vtenc_get_frame_info(sample_buffer, &is_key_frame);
     status = get_length_code_size(avctx, sample_buffer, &length_code_size);
@@ -715,26 +810,23 @@ static int vtenc_cm_to_avpacket(
 
     add_header = is_key_frame && !(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER);
 
-    size_t header_size = 0;
-    CMVideoFormatDescriptionRef vid_fmt;
     if(add_header){
         vid_fmt = CMSampleBufferGetFormatDescription(sample_buffer);
         if(!vid_fmt){
             av_log(avctx, AV_LOG_ERROR, "Cannot get format description.\n");
         }
 
-        int status = get_params_info(avctx, vid_fmt, &header_size);
+        int status = get_params_size(avctx, vid_fmt, &header_size);
         if(status) return status;
     }
 
-    CMBlockBufferRef block = CMSampleBufferGetDataBuffer(sample_buffer);
+    block = CMSampleBufferGetDataBuffer(sample_buffer);
     if(!block){
         av_log(avctx, AV_LOG_ERROR, "Could not get block buffer from sample buffer.\n");
         return AVERROR_EXTERNAL;
     }
 
-    size_t in_buf_size;
-    char* buf_data;
+
     status = CMBlockBufferGetDataPointer(block, 0, &in_buf_size, NULL, &buf_data);
     if(status){
         av_log(avctx, AV_LOG_ERROR, "Error: cannot get data pointer: %d\n", status);
@@ -749,8 +841,6 @@ static int vtenc_cm_to_avpacket(
     av_init_packet(pkt);
 
     if(can_reuse_cmbuffer){
-        CFRetain(block);
-
         AVBufferRef* buf_ref = av_buffer_create(
             buf_data,
             out_buf_size,
@@ -759,10 +849,9 @@ static int vtenc_cm_to_avpacket(
             0
         );
 
-        if(!buf_ref){
-            CFRelease(block);
-            return AVERROR(ENOMEM);
-        }
+        if(!buf_ref) return AVERROR(ENOMEM);
+
+        CFRetain(block);
 
         pkt->buf  = buf_ref;
         pkt->data = buf_data;
@@ -808,11 +897,11 @@ static int vtenc_cm_to_avpacket(
         pkt->flags |= AV_PKT_FLAG_KEY;
     }
 
-    const CMTime pts = CMSampleBufferGetPresentationTimeStamp(sample_buffer);
-    const CMTime dts = CMSampleBufferGetDecodeTimeStamp      (sample_buffer);
+    pts = CMSampleBufferGetPresentationTimeStamp(sample_buffer);
+    dts = CMSampleBufferGetDecodeTimeStamp      (sample_buffer);
 
-    int64_t dts_delta = vtctx->dts_delta >= 0 ? vtctx->dts_delta : 0;
-    int64_t time_base_num = avctx->time_base.num;
+    dts_delta = vtctx->dts_delta >= 0 ? vtctx->dts_delta : 0;
+    time_base_num = avctx->time_base.num;
     pkt->pts = pts.value / time_base_num;
     pkt->dts = dts.value / time_base_num - dts_delta;
 
@@ -828,8 +917,7 @@ static int get_cv_pixel_info(
     size_t* heights,
     size_t* strides)
 {
-    VTEncContext* vtctx = (VTEncContext*)avctx->priv_data;
-
+    VTEncContext* vtctx = avctx->priv_data;
     int av_format      = avctx->pix_fmt;
     int av_color_range = avctx->color_range;
 
@@ -919,15 +1007,30 @@ static int get_cv_pixel_info(
     return 0;
 }
 
-static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AVFrame* frame){
-    av_assert0(frame);
+static void free_avframe(
+    void *CV_NULLABLE release_ctx,
+    const void *CV_NULLABLE data,
+    size_t size,
+    size_t plane_count,
+    const void *CV_NULLABLE plane_addresses[])
+{
+    AVFrame* frame = release_ctx;
+    av_frame_free(&frame);
+}
 
+static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AVFrame* frame){
     int plane_count;
     int color;
     size_t widths [AV_NUM_DATA_POINTERS];
     size_t heights[AV_NUM_DATA_POINTERS];
     size_t strides[AV_NUM_DATA_POINTERS];
-    int status = get_cv_pixel_info(avctx, frame, &color, &plane_count, widths, heights, strides);
+    int status;
+    CVPixelBufferRef cv_img;
+    CMTime time;
+
+    av_assert0(frame);
+
+    status = get_cv_pixel_info(avctx, frame, &color, &plane_count, widths, heights, strides);
     if(status){
         av_log(
                avctx,
@@ -940,21 +1043,29 @@ static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AV
         return AVERROR_EXTERNAL;
     }
 
-    CVPixelBufferRef cv_img;
+    AVFrame* enc_frame = av_frame_alloc();
+    if(!enc_frame) return AVERROR(ENOMEM);
+
+    status = av_frame_ref(enc_frame, frame);
+    if(status){
+        av_frame_free(&enc_frame);
+        return status;
+    }
+
     status = CVPixelBufferCreateWithPlanarBytes(
         kCFAllocatorDefault,
-        frame->width,
-        frame->height,
+        enc_frame->width,
+        enc_frame->height,
         color,
         NULL,
         0,
         plane_count,
-        (void**)frame->data,
+        (void**)enc_frame->data,
         widths,
         heights,
         strides,
-        NULL,
-        NULL,
+        free_avframe,
+        enc_frame,
         NULL,
         &cv_img
     );
@@ -964,8 +1075,7 @@ static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AV
         return AVERROR_EXTERNAL;
     }
 
-    CMTime time = CMTimeMake(frame->pts * avctx->time_base.num, avctx->time_base.den);
-    VTEncodeInfoFlags flags = 0;
+    time = CMTimeMake(frame->pts * avctx->time_base.num, avctx->time_base.den);
     status = VTCompressionSessionEncodeFrame(
         vtctx->session,
         cv_img,
@@ -973,7 +1083,7 @@ static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AV
         kCMTimeInvalid,
         NULL,
         NULL,
-        &flags
+        NULL
     );
 
     CFRelease(cv_img);
@@ -992,8 +1102,10 @@ static av_cold int vtenc_frame(
     const AVFrame* frame,
     int* got_packet)
 {
-    VTEncContext* vtctx = (VTEncContext*)avctx->priv_data;
+    VTEncContext* vtctx = avctx->priv_data;
+    bool get_frame;
     int status;
+    CMSampleBufferRef buf = NULL;
 
     if(frame){
         status = vtenc_send_frame(avctx, vtctx, frame);
@@ -1025,13 +1137,12 @@ static av_cold int vtenc_frame(
     }
 
     *got_packet = 0;
-    bool get_frame = vtctx->dts_delta >= 0 || !frame;
+    get_frame = vtctx->dts_delta >= 0 || !frame;
     if(!get_frame){
         status = 0;
         goto end_nopkt;
     }
 
-    CMSampleBufferRef buf = NULL;
     status = vtenc_q_pop(vtctx, !frame, &buf);
     if(status) goto end_nopkt;
     if(!buf)   goto end_nopkt;
@@ -1049,7 +1160,7 @@ end_nopkt:
 }
 
 static av_cold int vtenc_close(AVCodecContext* avctx){
-    VTEncContext* vtctx = (VTEncContext*)avctx->priv_data;
+    VTEncContext* vtctx = avctx->priv_data;
 
     if(!vtctx->session) return 0;
 
-- 
2.4.9 (Apple Git-60)



More information about the ffmpeg-devel mailing list