From a259501e5a6ed07d76ce5d615123148b9b68d9f8 Mon Sep 17 00:00:00 2001 From: Rick Kern Date: Fri, 24 Jun 2016 11:00:17 -0400 Subject: [PATCH] lavd/avfoundation: Fix skewed video output Fixes ticket #5654. The linesize can be greater than the minimum required. This copies the frame taking linesize into account. Signed-off-by: Rick Kern --- libavdevice/avfoundation.m | 56 +++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index a540f6a079..98552ac29d 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -35,6 +35,7 @@ #include "libavutil/internal.h" #include "libavutil/parseutils.h" #include "libavutil/time.h" +#include "libavutil/imgutils.h" #include "avdevice.h" static const int avf_time_base = 1000000; @@ -892,6 +893,49 @@ fail: return AVERROR(EIO); } +static int copy_cvpixelbuffer(AVFormatContext *s, + CVPixelBufferRef image_buffer, + AVPacket *pkt) +{ + AVFContext *ctx = s->priv_data; + int src_linesize[4]; + const uint8_t *src_data[4]; + int width = CVPixelBufferGetWidth(image_buffer); + int height = CVPixelBufferGetHeight(image_buffer); + int status; + + memset(src_linesize, 0, sizeof(src_linesize)); + memset(src_data, 0, sizeof(src_data)); + + status = CVPixelBufferLockBaseAddress(image_buffer, 0); + if (status != kCVReturnSuccess) { + av_log(s, AV_LOG_ERROR, "Could not lock base address: %d\n", status); + return AVERROR_EXTERNAL; + } + + if (CVPixelBufferIsPlanar(image_buffer)) { + size_t plane_count = CVPixelBufferGetPlaneCount(image_buffer); + int i; + for(i = 0; i < plane_count; i++){ + src_linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(image_buffer, i); + src_data[i] = CVPixelBufferGetBaseAddressOfPlane(image_buffer, i); + } + } else { + src_linesize[0] = CVPixelBufferGetBytesPerRow(image_buffer); + src_data[0] = CVPixelBufferGetBaseAddress(image_buffer); + } + + status = av_image_copy_to_buffer(pkt->data, pkt->size, + src_data, src_linesize, + ctx->pixel_format, width, height, 1); + + + + CVPixelBufferUnlockBaseAddress(image_buffer, 0); + + return status; +} + static int avf_read_packet(AVFormatContext *s, AVPacket *pkt) { AVFContext* ctx = (AVFContext*)s->priv_data; @@ -903,7 +947,7 @@ static int avf_read_packet(AVFormatContext *s, AVPacket *pkt) image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame); if (ctx->current_frame != nil) { - void *data; + int status; if (av_new_packet(pkt, (int)CVPixelBufferGetDataSize(image_buffer)) < 0) { return AVERROR(EIO); } @@ -919,14 +963,12 @@ static int avf_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->stream_index = ctx->video_stream_index; pkt->flags |= AV_PKT_FLAG_KEY; - CVPixelBufferLockBaseAddress(image_buffer, 0); - - data = CVPixelBufferGetBaseAddress(image_buffer); - memcpy(pkt->data, data, pkt->size); - - CVPixelBufferUnlockBaseAddress(image_buffer, 0); + status = copy_cvpixelbuffer(s, image_buffer, pkt); CFRelease(ctx->current_frame); ctx->current_frame = nil; + + if (status < 0) + return status; } else if (ctx->current_audio_frame != nil) { CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(ctx->current_audio_frame); int block_buffer_size = CMBlockBufferGetDataLength(block_buffer);