From: Rick Kern <ker...@gmail.com> Signed-off-by: Rick Kern <ker...@gmail.com> --- libavcodec/vtenc.c | 308 ++++++++++++++++++++++++++--------------------------- 1 file changed, 154 insertions(+), 154 deletions(-)
diff --git a/libavcodec/vtenc.c b/libavcodec/vtenc.c index f497c38..b363492 100644 --- a/libavcodec/vtenc.c +++ b/libavcodec/vtenc.c @@ -44,20 +44,20 @@ typedef struct BufNode{ typedef struct VTEncContext{ AVClass* class; VTCompressionSessionRef session; - + pthread_mutex_t lock; pthread_cond_t cv_sample_sent; int async_error; - + BufNode* q_head; BufNode* q_tail; - + int64_t frame_ct_out; int64_t frame_ct_in; - + int64_t first_pts; int64_t dts_delta; - + char* profile; char* level; @@ -68,62 +68,62 @@ typedef struct VTEncContext{ static void set_async_error(VTEncContext* vtctx, int err){ pthread_mutex_lock(&vtctx->lock); - + vtctx->async_error = err; - + BufNode* info = vtctx->q_head; vtctx->q_head = vtctx->q_tail = NULL; - + while(info){ CFRelease(info->cm_buffer); - + BufNode* next = info->next; free(info); info = next; } - + pthread_mutex_unlock(&vtctx->lock); } static int vtenc_q_pop(VTEncContext* vtctx, bool wait, CMSampleBufferRef* buf){ pthread_mutex_lock(&vtctx->lock); - + if(vtctx->async_error){ pthread_mutex_unlock(&vtctx->lock); return vtctx->async_error; } - + if(vtctx->flushing && vtctx->frame_ct_in == vtctx->frame_ct_out){ *buf = NULL; - + pthread_mutex_unlock(&vtctx->lock); return 0; } - + if(!vtctx->q_head && wait){ pthread_cond_wait(&vtctx->cv_sample_sent, &vtctx->lock); } - + if(!vtctx->q_head){ pthread_mutex_unlock(&vtctx->lock); *buf = NULL; return 0; } - + BufNode* info = vtctx->q_head; vtctx->q_head = vtctx->q_head->next; if(!vtctx->q_head){ vtctx->q_tail = NULL; } - + pthread_mutex_unlock(&vtctx->lock); - + CMSampleBufferRef buffer = info->cm_buffer; free(info); - + vtctx->frame_ct_out++; *buf = buffer; - + return 0; } @@ -133,19 +133,19 @@ static void vtenc_q_push(VTEncContext* vtctx, CMSampleBufferRef buffer){ CFRetain(buffer); info->cm_buffer = buffer; info->next = NULL; - + pthread_mutex_lock(&vtctx->lock); 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_tail->next = info; vtctx->q_tail = info; - + pthread_mutex_unlock(&vtctx->lock); } @@ -177,13 +177,13 @@ static int get_params_info( { size_t total_size = 0; size_t ps_count; - + 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++){ const uint8_t* ps; size_t ps_size; @@ -192,7 +192,7 @@ static int get_params_info( av_log(avctx, AV_LOG_ERROR, "Error getting parameter set size for index %zd: %d\n", i, status); return AVERROR_EXTERNAL; } - + total_size += ps_size + sizeof(start_code); } @@ -212,7 +212,7 @@ static int copy_param_sets( 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++){ const uint8_t* ps; @@ -222,20 +222,20 @@ static int copy_param_sets( 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; if(dst_size < next_offset){ av_log(avctx, AV_LOG_ERROR, "Error: buffer too small for parameter sets.\n"); return AVERROR_BUFFER_TOO_SMALL; } - + memcpy(dst + offset, start_code, sizeof(start_code)); offset += sizeof(start_code); - + memcpy(dst + offset, ps, ps_size); offset = next_offset; } - + return 0; } @@ -246,7 +246,7 @@ static int set_extradata(AVCodecContext* avctx, CMSampleBufferRef sample_buffer) 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); @@ -254,19 +254,19 @@ static int set_extradata(AVCodecContext* avctx, CMSampleBufferRef sample_buffer) av_log(avctx, AV_LOG_ERROR, "Could not get parameter sets.\n"); return status; } - + avctx->extradata = malloc(total_size); if(!avctx->extradata){ return AVERROR(ENOMEM); } avctx->extradata_size = total_size; - + status = copy_param_sets(avctx, vid_fmt, avctx->extradata, total_size); if(status){ av_log(avctx, AV_LOG_ERROR, "Could not copy param sets.\n"); return status; } - + return 0; } @@ -280,18 +280,18 @@ static av_cold void vtenc_output_callback( av_assert0(ctx); AVCodecContext* avctx = (AVCodecContext*)ctx; VTEncContext* vtctx = (VTEncContext*)avctx->priv_data; - + if(vtctx->async_error){ CFRelease(sample_buffer); return; } - + if(status){ av_log(avctx, AV_LOG_ERROR, "Error encoding frame: %d\n", status); set_async_error(vtctx, AVERROR_EXTERNAL); return; } - + if(!avctx->extradata && (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)){ int set_status = set_extradata(avctx, sample_buffer); if(set_status){ @@ -299,7 +299,7 @@ static av_cold void vtenc_output_callback( return; } } - + vtenc_q_push(vtctx, sample_buffer); } @@ -314,21 +314,21 @@ static int get_length_code_size( 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); if(status){ av_log(avctx, AV_LOG_ERROR, "Error getting length code size: %d\n", status); return AVERROR_EXTERNAL; } - + *size = isize; return 0; } static bool get_h264_profile(AVCodecContext* avctx, int* profile_num){ VTEncContext* vtctx = (VTEncContext*)avctx->priv_data; - + const char* profile = vtctx->profile; if(!profile){ *profile_num = FF_PROFILE_UNKNOWN; @@ -346,36 +346,36 @@ static bool get_h264_profile(AVCodecContext* avctx, int* profile_num){ av_log(avctx, AV_LOG_ERROR, "Unknown profile '%s'\n", profile); return false; } - + return true; } static bool get_h264_level(AVCodecContext* avctx, int* level_num){ VTEncContext* vtctx = (VTEncContext*)avctx->priv_data; - + if(!vtctx->level){ *level_num = FF_LEVEL_UNKNOWN; 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; } - + *level_num = (int)(major * 10 + minor); return true; } @@ -391,26 +391,26 @@ static bool getVTProfileLevel(AVCodecContext* avctx, CFStringRef* profileLevelVa int profile; int level; - + if(!get_h264_profile(avctx, &profile)){ return AVERROR(EINVAL); } - + if(!get_h264_level(avctx, &level)){ return AVERROR(EINVAL); } - + if(profile == FF_LEVEL_UNKNOWN && level != FF_LEVEL_UNKNOWN) { profile = vtctx->has_b_frames ? FF_PROFILE_H264_MAIN : FF_PROFILE_H264_BASELINE; } - + switch(profile){ case FF_PROFILE_UNKNOWN: *profileLevelVal = NULL; return true; - + case FF_PROFILE_H264_BASELINE: switch(level){ case FF_LEVEL_UNKNOWN: *profileLevelVal = kVTProfileLevel_H264_Baseline_AutoLevel; break; @@ -429,7 +429,7 @@ static bool getVTProfileLevel(AVCodecContext* avctx, CFStringRef* profileLevelVa return false; } return true; - + case FF_PROFILE_H264_MAIN: switch(level){ case FF_LEVEL_UNKNOWN: *profileLevelVal = kVTProfileLevel_H264_Main_AutoLevel; break; @@ -447,7 +447,7 @@ static bool getVTProfileLevel(AVCodecContext* avctx, CFStringRef* profileLevelVa return false; } return true; - + case FF_PROFILE_H264_HIGH: switch(level){ case FF_LEVEL_UNKNOWN: *profileLevelVal = kVTProfileLevel_H264_High_AutoLevel; break; @@ -465,7 +465,7 @@ static bool getVTProfileLevel(AVCodecContext* avctx, CFStringRef* profileLevelVa return false; } return true; - + default: av_log(avctx, AV_LOG_ERROR, "Unrecognized profile %s (%d)\n", vtctx->profile, profile); return false; @@ -476,32 +476,32 @@ static av_cold int vtenc_init(AVCodecContext* avctx){ VTEncContext* vtctx = (VTEncContext*)avctx->priv_data; CMVideoCodecType codec_type; OSStatus status; - + codec_type = get_cm_codec_type(avctx->codec_id); if(!codec_type){ av_log(avctx, AV_LOG_ERROR, "Error: no mapping for AVCodecID %d\n", avctx->codec_id); return AVERROR(EINVAL); } - + vtctx->has_b_frames = avctx->has_b_frames && avctx->max_b_frames > 0; - + CFStringRef profileLevel; if(!getVTProfileLevel(avctx, &profileLevel)){ return AVERROR(EINVAL); } - + vtctx->session = NULL; - + CFMutableDictionaryRef enc_info = CFDictionaryCreateMutable( kCFAllocatorDefault, 20, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); - + CFDictionarySetValue(enc_info, kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder, kCFBooleanTrue); CFDictionarySetValue(enc_info, kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, kCFBooleanTrue); - + status = VTCompressionSessionCreate( kCFAllocatorDefault, avctx->width, @@ -517,7 +517,7 @@ static av_cold int vtenc_init(AVCodecContext* avctx){ if(status != 0 || !vtctx->session){ CFDictionaryRemoveValue(enc_info, kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder); - + status = VTCompressionSessionCreate( kCFAllocatorDefault, avctx->width, @@ -531,60 +531,60 @@ static av_cold int vtenc_init(AVCodecContext* avctx){ &vtctx->session ); } - + 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); status = VTSessionSetProperty(vtctx->session, kVTCompressionPropertyKey_AverageBitRate, bit_rate_num); CFRelease(bit_rate_num); - + if(status){ av_log(avctx, AV_LOG_ERROR, "Error setting bitrate property: %d\n", status); return AVERROR_EXTERNAL; } - + if(profileLevel){ status = VTSessionSetProperty(vtctx->session, kVTCompressionPropertyKey_ProfileLevel, profileLevel); - + if(status){ av_log(avctx, AV_LOG_ERROR, "Error setting profile/level property: %d\n", status); return AVERROR_EXTERNAL; } } - + if(avctx->gop_size > 0){ CFNumberRef interval = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &avctx->gop_size); status = VTSessionSetProperty(vtctx->session, kVTCompressionPropertyKey_MaxKeyFrameInterval, interval); - + if(status){ av_log(avctx, AV_LOG_ERROR, "Error setting 'max key-frame interval' property: %d\n", status); return AVERROR_EXTERNAL; } } - + if(!vtctx->has_b_frames){ status = VTSessionSetProperty(vtctx->session, kVTCompressionPropertyKey_AllowFrameReordering, kCFBooleanFalse); - + if(status){ av_log(avctx, AV_LOG_ERROR, "Error setting 'allow frame reordering' property: %d\n", status); return AVERROR_EXTERNAL; } } - + status = VTCompressionSessionPrepareToEncodeFrames(vtctx->session); if(status){ av_log(avctx, AV_LOG_ERROR, "Error: cannot prepare encoder: %d\n", status); return AVERROR_EXTERNAL; } - + pthread_mutex_init(&vtctx->lock, NULL); pthread_cond_init(&vtctx->cv_sample_sent, NULL); vtctx->dts_delta = vtctx->has_b_frames ? -1 : 0; - + return 0; } @@ -599,9 +599,9 @@ static void vtenc_get_frame_info( *is_key_frame = true; return; } - + CFDictionaryRef attachment = (CFDictionaryRef)CFArrayGetValueAtIndex(attachments, 0); - + CFBooleanRef not_sync; if(CFDictionaryGetValueIfPresent(attachment, kCMSampleAttachmentKey_NotSync, (const void**)¬_sync)){ *is_key_frame = !CFBooleanGetValue(not_sync); @@ -616,7 +616,7 @@ static int replace_length_codes(size_t length_code_size, uint8_t* data, size_t s av_log(NULL, AV_LOG_ERROR, "lc != sizeof\n"); return AVERROR_BUFFER_TOO_SMALL; } - + size_t remaining_size = size; while(remaining_size > 0){ size_t box_len = 0; @@ -624,17 +624,17 @@ static int replace_length_codes(size_t length_code_size, uint8_t* data, size_t s 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"); AVERROR_BUFFER_TOO_SMALL; } - + memcpy(data, start_code, sizeof(start_code)); data += box_len + sizeof(start_code); remaining_size -= box_len + sizeof(start_code); } - + return 0; } @@ -649,7 +649,7 @@ static int copy_replace_length_codes( 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){ @@ -658,31 +658,31 @@ static int copy_replace_length_codes( 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); - + if(remaining_src_size < curr_src_len){ return AVERROR_BUFFER_TOO_SMALL; } - + if(remaining_dst_size < curr_dst_len){ return AVERROR_BUFFER_TOO_SMALL; } - + uint8_t* dst_box = dst_data + sizeof(start_code); const uint8_t* src_box = src_data + length_code_size; - + memcpy(dst_data, start_code, sizeof(start_code)); memcpy(dst_box, src_box, box_len); - + src_data += curr_src_len; dst_data += curr_dst_len; - + remaining_src_size -= curr_src_len; remaining_dst_size -= curr_dst_len; } - + return 0; } @@ -692,18 +692,18 @@ static int vtenc_cm_to_avpacket( AVPacket* pkt) { VTEncContext* vtctx = (VTEncContext*)avctx->priv_data; - + 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); if(status) return status; - + add_header = is_key_frame && !(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER); - + size_t header_size = 0; CMVideoFormatDescriptionRef vid_fmt; if(add_header){ @@ -711,17 +711,17 @@ static int vtenc_cm_to_avpacket( if(!vid_fmt){ av_log(avctx, AV_LOG_ERROR, "Cannot get format description.\n"); } - + int status = get_params_info(avctx, vid_fmt, &header_size); if(status) return status; } - + CMBlockBufferRef 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); @@ -729,17 +729,17 @@ static int vtenc_cm_to_avpacket( av_log(avctx, AV_LOG_ERROR, "Error: cannot get data pointer: %d\n", status); return AVERROR_EXTERNAL; } - + size_t out_buf_size = header_size + in_buf_size; bool can_reuse_cmbuffer = !add_header && !pkt->data && length_code_size == sizeof(start_code); - + av_init_packet(pkt); - + if(can_reuse_cmbuffer){ CFRetain(block); - + AVBufferRef* buf_ref = av_buffer_create( buf_data, out_buf_size, @@ -747,16 +747,16 @@ static int vtenc_cm_to_avpacket( block, 0 ); - + if(!buf_ref){ CFRelease(block); return AVERROR(ENOMEM); } - + pkt->buf = buf_ref; pkt->data = buf_data; pkt->size = in_buf_size; - + status = replace_length_codes(length_code_size, pkt->data, pkt->size); if(status){ av_log(avctx, AV_LOG_ERROR, "Error replacing length codes: %d\n", status); @@ -768,17 +768,17 @@ static int vtenc_cm_to_avpacket( status = av_new_packet(pkt, out_buf_size); if(status) return status; } - + if(pkt->size < out_buf_size){ av_log(avctx, AV_LOG_ERROR, "Error: packet's buffer is too small.\n"); return AVERROR_BUFFER_TOO_SMALL; } - + if(add_header){ status = copy_param_sets(avctx, vid_fmt, pkt->data, out_buf_size); if(status) return status; } - + status = copy_replace_length_codes( length_code_size, buf_data, @@ -786,7 +786,7 @@ static int vtenc_cm_to_avpacket( pkt->data + header_size, pkt->size - header_size ); - + if(status){ av_log(avctx, AV_LOG_ERROR, "Error copying packet data: %d", status); return status; @@ -796,15 +796,15 @@ static int vtenc_cm_to_avpacket( if(is_key_frame){ pkt->flags |= AV_PKT_FLAG_KEY; } - + const CMTime pts = CMSampleBufferGetPresentationTimeStamp(sample_buffer); const CMTime 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; pkt->pts = pts.value / time_base_num; pkt->dts = dts.value / time_base_num - dts_delta; - + return 0; } @@ -818,21 +818,21 @@ static int get_cv_pixel_info( size_t* strides) { VTEncContext* vtctx = (VTEncContext*)avctx->priv_data; - + int av_format = avctx->pix_fmt; int av_color_range = avctx->color_range; - + switch(av_format){ case AV_PIX_FMT_NV12: switch(av_color_range){ case AVCOL_RANGE_MPEG: *color = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; break; - + case AVCOL_RANGE_JPEG: *color = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange; break; - + default: if(!vtctx->warned_color_range){ vtctx->warned_color_range = true; @@ -840,28 +840,28 @@ static int get_cv_pixel_info( } *color = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; } - + *plane_count = 2; - + widths [0] = avctx->width; heights[0] = avctx->height; strides[0] = frame ? frame->linesize[0] : avctx->width; - + widths [1] = (avctx->width + 1) / 2; heights[1] = (avctx->height + 1) / 2; strides[1] = frame ? frame->linesize[1] : (avctx->width + 1) & -2; break; - + case AV_PIX_FMT_YUV420P: switch(av_color_range){ case AVCOL_RANGE_MPEG: *color = kCVPixelFormatType_420YpCbCr8Planar; break; - + case AVCOL_RANGE_JPEG: *color = kCVPixelFormatType_420YpCbCr8PlanarFullRange; break; - + default: if(!vtctx->warned_color_range){ vtctx->warned_color_range = true; @@ -869,48 +869,48 @@ static int get_cv_pixel_info( } *color = kCVPixelFormatType_420YpCbCr8Planar; } - + *plane_count = 3; - + widths [0] = avctx->width; heights[0] = avctx->height; strides[0] = frame ? frame->linesize[0] : avctx->width; - + widths [1] = (avctx->width + 1) / 2; heights[1] = (avctx->height + 1) / 2; strides[1] = frame ? frame->linesize[1] : (avctx->width + 1) / 2; - + widths [2] = (avctx->width + 1) / 2; heights[2] = (avctx->height + 1) / 2; strides[2] = frame ? frame->linesize[2] : (avctx->width + 1) / 2; break; - + case AV_PIX_FMT_YUVJ420P: *color = kCVPixelFormatType_420YpCbCr8PlanarFullRange; *plane_count = 3; - + widths [0] = avctx->width; heights[0] = avctx->height; strides[0] = frame ? frame->linesize[0] : avctx->width; - + widths [1] = (avctx->width + 1) / 2; heights[1] = (avctx->height + 1) / 2; strides[1] = frame ? frame->linesize[1] : (avctx->width + 1) / 2; - + widths [2] = (avctx->width + 1) / 2; heights[2] = (avctx->height + 1) / 2; strides[2] = frame ? frame->linesize[2] : (avctx->width + 1) / 2; break; - + default: return AVERROR(EINVAL); } - + return 0; } static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AVFrame* frame){ av_assert0(frame); - + int plane_count; int color; size_t widths [AV_NUM_DATA_POINTERS]; @@ -928,7 +928,7 @@ static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AV ); return AVERROR_EXTERNAL; } - + CVPixelBufferRef cv_img; status = CVPixelBufferCreateWithPlanarBytes( kCFAllocatorDefault, @@ -947,12 +947,12 @@ static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AV NULL, &cv_img ); - + if(status){ av_log(avctx, AV_LOG_ERROR, "Error: cannot create CVPixelBufferRef: %d\n", status); return AVERROR_EXTERNAL; } - + CMTime time = CMTimeMake(frame->pts * avctx->time_base.num, avctx->time_base.den); VTEncodeInfoFlags flags = 0; status = VTCompressionSessionEncodeFrame( @@ -964,14 +964,14 @@ static int vtenc_send_frame(AVCodecContext* avctx, VTEncContext* vtctx, const AV NULL, &flags ); - + CFRelease(cv_img); - + if(status){ av_log(avctx, AV_LOG_ERROR, "Error: cannot encode frame: %d\n", status); return AVERROR_EXTERNAL; } - + return 0; } @@ -983,27 +983,27 @@ static av_cold int vtenc_frame( { VTEncContext* vtctx = (VTEncContext*)avctx->priv_data; int status; - + if(frame){ status = vtenc_send_frame(avctx, vtctx, frame); - + if(status){ status = AVERROR_EXTERNAL; goto end_nopkt; } - + if(vtctx->frame_ct_in == 0){ vtctx->first_pts = frame->pts; } else if(vtctx->frame_ct_in == 1 && vtctx->has_b_frames){ vtctx->dts_delta = frame->pts - vtctx->first_pts; } - + vtctx->frame_ct_in++; } else if(!vtctx->flushing){ vtctx->flushing = true; - + status = VTCompressionSessionCompleteFrames(vtctx->session, kCMTimeIndefinite); if(status){ @@ -1012,26 +1012,26 @@ static av_cold int vtenc_frame( goto end_nopkt; } } - + *got_packet = 0; bool 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; - + status = vtenc_cm_to_avpacket(avctx, buf, pkt); CFRelease(buf); if(status) goto end_nopkt; - + *got_packet = 1; return 0; - + end_nopkt: av_packet_unref(pkt); return status; @@ -1039,15 +1039,15 @@ end_nopkt: static av_cold int vtenc_close(AVCodecContext* avctx){ VTEncContext* vtctx = (VTEncContext*)avctx->priv_data; - + if(!vtctx->session) return 0; - + VTCompressionSessionInvalidate(vtctx->session); pthread_cond_destroy(&vtctx->cv_sample_sent); pthread_mutex_destroy(&vtctx->lock); CFRelease(vtctx->session); vtctx->session = NULL; - + return 0; } -- 2.4.9 (Apple Git-60) _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel