diff options
Diffstat (limited to 'source/blender/imbuf/intern/anim_movie.c')
-rw-r--r-- | source/blender/imbuf/intern/anim_movie.c | 176 |
1 files changed, 39 insertions, 137 deletions
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 6a05b681c88..38dbb9bfc47 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -504,11 +504,6 @@ static ImBuf *avi_fetchibuf(struct anim *anim, int position) #ifdef WITH_FFMPEG -BLI_INLINE bool need_aligned_ffmpeg_buffer(struct anim *anim) -{ - return (anim->x & 31) != 0; -} - static int startffmpeg(struct anim *anim) { int i, video_stream_index; @@ -707,23 +702,20 @@ static int startffmpeg(struct anim *anim) anim->pFrameComplete = false; anim->pFrameDeinterlaced = av_frame_alloc(); anim->pFrameRGB = av_frame_alloc(); + anim->pFrameRGB->format = AV_PIX_FMT_RGBA; + anim->pFrameRGB->width = anim->x; + anim->pFrameRGB->height = anim->y; - if (need_aligned_ffmpeg_buffer(anim)) { - anim->pFrameRGB->format = AV_PIX_FMT_RGBA; - anim->pFrameRGB->width = anim->x; - anim->pFrameRGB->height = anim->y; - - if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) { - fprintf(stderr, "Could not allocate frame data.\n"); - avcodec_free_context(&anim->pCodecCtx); - avformat_close_input(&anim->pFormatCtx); - av_packet_free(&anim->cur_packet); - av_frame_free(&anim->pFrameRGB); - av_frame_free(&anim->pFrameDeinterlaced); - av_frame_free(&anim->pFrame); - anim->pCodecCtx = NULL; - return -1; - } + if (av_frame_get_buffer(anim->pFrameRGB, 0) < 0) { + fprintf(stderr, "Could not allocate frame data.\n"); + avcodec_free_context(&anim->pCodecCtx); + avformat_close_input(&anim->pFormatCtx); + av_packet_free(&anim->cur_packet); + av_frame_free(&anim->pFrameRGB); + av_frame_free(&anim->pFrameDeinterlaced); + av_frame_free(&anim->pFrame); + anim->pCodecCtx = NULL; + return -1; } if (av_image_get_buffer_size(AV_PIX_FMT_RGBA, anim->x, anim->y, 1) != anim->x * anim->y * 4) { @@ -851,92 +843,26 @@ static void ffmpeg_postprocess(struct anim *anim) } } - if (!need_aligned_ffmpeg_buffer(anim)) { - av_image_fill_arrays(anim->pFrameRGB->data, - anim->pFrameRGB->linesize, - (unsigned char *)ibuf->rect, - AV_PIX_FMT_RGBA, - anim->x, - anim->y, - 1); - } - -# if defined(__x86_64__) || defined(_M_X64) - /* Scale and flip image over Y axis in one go, using negative strides. - * This doesn't work with ARM/PowerPC though and may be misusing the API. - * Limit it x86_64 where it appears to work. - * http://trac.ffmpeg.org/ticket/9060 */ - int *dstStride = anim->pFrameRGB->linesize; - uint8_t **dst = anim->pFrameRGB->data; - const int dstStride2[4] = {-dstStride[0], 0, 0, 0}; - uint8_t *dst2[4] = {dst[0] + (anim->y - 1) * dstStride[0], 0, 0, 0}; - - sws_scale(anim->img_convert_ctx, - (const uint8_t *const *)input->data, - input->linesize, - 0, - anim->y, - dst2, - dstStride2); -# else - /* Scale with swscale. */ - int *dstStride = anim->pFrameRGB->linesize; - uint8_t **dst = anim->pFrameRGB->data; - const int dstStride2[4] = {dstStride[0], 0, 0, 0}; - uint8_t *dst2[4] = {dst[0], 0, 0, 0}; - int x, y, h, w; - unsigned char *bottom; - unsigned char *top; - sws_scale(anim->img_convert_ctx, (const uint8_t *const *)input->data, input->linesize, 0, anim->y, - dst2, - dstStride2); - - /* Flip destination image buffer over Y axis. */ - bottom = (unsigned char *)dst[0]; - top = bottom + anim->x * (anim->y - 1) * 4; - - h = (anim->y + 1) / 2; - w = anim->x; - - for (y = 0; y < h; y++) { - unsigned char tmp[4]; - unsigned int *tmp_l = (unsigned int *)tmp; - - for (x = 0; x < w; x++) { - tmp[0] = bottom[0]; - tmp[1] = bottom[1]; - tmp[2] = bottom[2]; - tmp[3] = bottom[3]; - - bottom[0] = top[0]; - bottom[1] = top[1]; - bottom[2] = top[2]; - bottom[3] = top[3]; - - *(unsigned int *)top = *tmp_l; - - bottom += 4; - top += 4; - } - top -= 8 * w; - } -# endif - - if (need_aligned_ffmpeg_buffer(anim)) { - uint8_t *buf_src = anim->pFrameRGB->data[0]; - uint8_t *buf_dst = (uint8_t *)ibuf->rect; - for (int y = 0; y < anim->y; y++) { - memcpy(buf_dst, buf_src, anim->x * 4); - buf_dst += anim->x * 4; - buf_src += anim->pFrameRGB->linesize[0]; - } - } - + anim->pFrameRGB->data, + anim->pFrameRGB->linesize); + + /* Copy the valid bytes from the aligned buffer vertically flipped into ImBuf */ + int aligned_stride = anim->pFrameRGB->linesize[0]; + const uint8_t *const src[4] = { + anim->pFrameRGB->data[0] + (anim->y - 1) * aligned_stride, 0, 0, 0}; + /* NOTE: Negative linesize is used to copy and flip image at once with function + * `av_image_copy_to_buffer`. This could cause issues in future and image may need to be flipped + * explicitly. */ + const int src_linesize[4] = {-anim->pFrameRGB->linesize[0], 0, 0, 0}; + int dst_size = av_image_get_buffer_size( + anim->pFrameRGB->format, anim->pFrameRGB->width, anim->pFrameRGB->height, 1); + av_image_copy_to_buffer( + (uint8_t *)ibuf->rect, dst_size, src, src_linesize, AV_PIX_FMT_RGBA, anim->x, anim->y, 1); if (filter_y) { IMB_filtery(ibuf); } @@ -1067,21 +993,23 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx) return false; } -static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search) +static double ffmpeg_steps_per_frame_get(struct anim *anim) { AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - AVRational frame_rate = v_st->r_frame_rate; AVRational time_base = v_st->time_base; - double steps_per_frame = (double)(frame_rate.den * time_base.den) / - (double)(frame_rate.num * time_base.num); + AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, NULL); + return av_q2d(av_inv_q(av_mul_q(frame_rate, time_base))); + ; +} + +static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search) +{ /* Step back half a frame position to make sure that we get the requested * frame and not the one after it. This is a workaround as ffmpeg will * sometimes not seek to a frame after the requested pts even if * AVSEEK_FLAG_BACKWARD is specified. */ - int64_t pts = pts_to_search - (steps_per_frame / 2); - - return pts; + return pts_to_search - (ffmpeg_steps_per_frame_get(anim) / 2); } /* This gives us an estimate of which pts our requested frame will have. @@ -1100,13 +1028,8 @@ static int64_t ffmpeg_get_pts_to_search(struct anim *anim, else { AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; int64_t start_pts = v_st->start_time; - AVRational frame_rate = v_st->r_frame_rate; - AVRational time_base = v_st->time_base; - - double steps_per_frame = (double)(frame_rate.den * time_base.den) / - (double)(frame_rate.num * time_base.num); - pts_to_search = round(position * steps_per_frame); + pts_to_search = round(position * ffmpeg_steps_per_frame_get(anim)); if (start_pts != AV_NOPTS_VALUE) { pts_to_search += start_pts; @@ -1196,13 +1119,6 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t *requested_pts, int64_t pts_to_search) { - AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream]; - AVRational frame_rate = v_st->r_frame_rate; - AVRational time_base = v_st->time_base; - - double steps_per_frame = (double)(frame_rate.den * time_base.den) / - (double)(frame_rate.num * time_base.num); - int64_t current_pts = *requested_pts; int64_t offset = 0; @@ -1210,7 +1126,7 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, /* Step backward frame by frame until we find the key frame we are looking for. */ while (current_pts != 0) { - current_pts = *requested_pts - (int64_t)round(offset * steps_per_frame); + current_pts = *requested_pts - (int64_t)round(offset * ffmpeg_steps_per_frame_get(anim)); current_pts = MAX2(current_pts, 0); /* Seek to timestamp. */ @@ -1482,20 +1398,6 @@ static void free_anim_ffmpeg(struct anim *anim) av_packet_free(&anim->cur_packet); av_frame_free(&anim->pFrame); - - if (!need_aligned_ffmpeg_buffer(anim)) { - /* If there's no need for own aligned buffer it means that FFmpeg's - * frame shares the same buffer as temporary ImBuf. In this case we - * should not free the buffer when freeing the FFmpeg buffer. - */ - av_image_fill_arrays(anim->pFrameRGB->data, - anim->pFrameRGB->linesize, - NULL, - AV_PIX_FMT_RGBA, - anim->x, - anim->y, - 1); - } av_frame_free(&anim->pFrameRGB); av_frame_free(&anim->pFrameDeinterlaced); |