diff options
Diffstat (limited to 'source/blender/imbuf')
-rw-r--r-- | source/blender/imbuf/CMakeLists.txt | 6 | ||||
-rw-r--r-- | source/blender/imbuf/intern/IMB_anim.h | 2 | ||||
-rw-r--r-- | source/blender/imbuf/intern/anim_movie.c | 161 | ||||
-rw-r--r-- | source/blender/imbuf/intern/indexer.c | 241 | ||||
-rw-r--r-- | source/blender/imbuf/intern/util.c | 16 |
5 files changed, 224 insertions, 202 deletions
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index 7ce795280a3..be0e364c85f 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -166,12 +166,6 @@ if(WITH_CODEC_FFMPEG) ${OPENJPEG_LIBRARIES} ) add_definitions(-DWITH_FFMPEG) - - remove_strict_c_flags_file( - intern/anim_movie.c - intern/indexer.c - intern/util.c - ) endif() if(WITH_IMAGE_DDS) diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h index 1239d3881de..7d7864306a1 100644 --- a/source/blender/imbuf/intern/IMB_anim.h +++ b/source/blender/imbuf/intern/IMB_anim.h @@ -135,7 +135,7 @@ struct anim { struct ImBuf *last_frame; int64_t last_pts; int64_t next_pts; - AVPacket next_packet; + AVPacket *next_packet; #endif char index_dir[768]; diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 432b62d172a..cdf6ca5c181 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -79,6 +79,7 @@ # include <libavcodec/avcodec.h> # include <libavformat/avformat.h> +# include <libavutil/imgutils.h> # include <libavutil/rational.h> # include <libswscale/swscale.h> @@ -519,12 +520,10 @@ static int startffmpeg(struct anim *anim) double frs_den; int streamcount; -# ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT /* The following for color space determination */ int srcRange, dstRange, brightness, contrast, saturation; int *table; const int *inv_table; -# endif if (anim == NULL) { return (-1); @@ -547,7 +546,7 @@ static int startffmpeg(struct anim *anim) video_stream_index = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) { - if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (streamcount > 0) { streamcount--; continue; @@ -563,16 +562,17 @@ static int startffmpeg(struct anim *anim) } video_stream = pFormatCtx->streams[video_stream_index]; - pCodecCtx = video_stream->codec; /* Find the decoder for the video stream */ - pCodec = avcodec_find_decoder(pCodecCtx->codec_id); + pCodec = avcodec_find_decoder(video_stream->codecpar->codec_id); if (pCodec == NULL) { avformat_close_input(&pFormatCtx); return -1; } - pCodecCtx->workaround_bugs = 1; + pCodecCtx = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(pCodecCtx, video_stream->codecpar); + pCodecCtx->workaround_bugs = FF_BUG_AUTODETECT; if (pCodec->capabilities & AV_CODEC_CAP_AUTO_THREADS) { pCodecCtx->thread_count = 0; @@ -593,7 +593,7 @@ static int startffmpeg(struct anim *anim) return -1; } if (pCodecCtx->pix_fmt == AV_PIX_FMT_NONE) { - avcodec_close(anim->pCodecCtx); + avcodec_free_context(&anim->pCodecCtx); avformat_close_input(&pFormatCtx); return -1; } @@ -639,7 +639,7 @@ static int startffmpeg(struct anim *anim) anim->params = 0; anim->x = pCodecCtx->width; - anim->y = av_get_cropped_height_from_codec(pCodecCtx); + anim->y = pCodecCtx->height; anim->pFormatCtx = pFormatCtx; anim->pCodecCtx = pCodecCtx; @@ -654,7 +654,8 @@ static int startffmpeg(struct anim *anim) anim->last_frame = 0; anim->last_pts = -1; anim->next_pts = -1; - anim->next_packet.stream_index = -1; + anim->next_packet = av_packet_alloc(); + anim->next_packet->stream_index = -1; anim->pFrame = av_frame_alloc(); anim->pFrameComplete = false; @@ -668,8 +669,9 @@ static int startffmpeg(struct anim *anim) if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) { fprintf(stderr, "Could not allocate frame data.\n"); - avcodec_close(anim->pCodecCtx); + avcodec_free_context(&anim->pCodecCtx); avformat_close_input(&anim->pFormatCtx); + av_packet_free(&anim->next_packet); av_frame_free(&anim->pFrameRGB); av_frame_free(&anim->pFrameDeinterlaced); av_frame_free(&anim->pFrame); @@ -678,10 +680,11 @@ static int startffmpeg(struct anim *anim) } } - if (avpicture_get_size(AV_PIX_FMT_RGBA, anim->x, anim->y) != anim->x * anim->y * 4) { + if (av_image_get_buffer_size(AV_PIX_FMT_RGBA, anim->x, anim->y, 1) != anim->x * anim->y * 4) { fprintf(stderr, "ffmpeg has changed alloc scheme ... ARGHHH!\n"); - avcodec_close(anim->pCodecCtx); + avcodec_free_context(&anim->pCodecCtx); avformat_close_input(&anim->pFormatCtx); + av_packet_free(&anim->next_packet); av_frame_free(&anim->pFrameRGB); av_frame_free(&anim->pFrameDeinterlaced); av_frame_free(&anim->pFrame); @@ -690,14 +693,17 @@ static int startffmpeg(struct anim *anim) } if (anim->ib_flags & IB_animdeinterlace) { - avpicture_fill((AVPicture *)anim->pFrameDeinterlaced, - MEM_callocN(avpicture_get_size(anim->pCodecCtx->pix_fmt, - anim->pCodecCtx->width, - anim->pCodecCtx->height), - "ffmpeg deinterlace"), - anim->pCodecCtx->pix_fmt, - anim->pCodecCtx->width, - anim->pCodecCtx->height); + av_image_fill_arrays(anim->pFrameDeinterlaced->data, + anim->pFrameDeinterlaced->linesize, + MEM_callocN(av_image_get_buffer_size(anim->pCodecCtx->pix_fmt, + anim->pCodecCtx->width, + anim->pCodecCtx->height, + 1), + "ffmpeg deinterlace"), + anim->pCodecCtx->pix_fmt, + anim->pCodecCtx->width, + anim->pCodecCtx->height, + 1); } if (pCodecCtx->has_b_frames) { @@ -720,8 +726,9 @@ static int startffmpeg(struct anim *anim) if (!anim->img_convert_ctx) { fprintf(stderr, "Can't transform color space??? Bailing out...\n"); - avcodec_close(anim->pCodecCtx); + avcodec_free_context(&anim->pCodecCtx); avformat_close_input(&anim->pFormatCtx); + av_packet_free(&anim->next_packet); av_frame_free(&anim->pFrameRGB); av_frame_free(&anim->pFrameDeinterlaced); av_frame_free(&anim->pFrame); @@ -729,7 +736,6 @@ static int startffmpeg(struct anim *anim) return -1; } -# ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT /* Try do detect if input has 0-255 YCbCR range (JFIF Jpeg MotionJpeg) */ if (!sws_getColorspaceDetails(anim->img_convert_ctx, (int **)&inv_table, @@ -756,7 +762,6 @@ static int startffmpeg(struct anim *anim) else { fprintf(stderr, "Warning: Could not set libswscale colorspace details.\n"); } -# endif return 0; } @@ -795,11 +800,11 @@ static void ffmpeg_postprocess(struct anim *anim) input->data[3]); if (anim->ib_flags & IB_animdeinterlace) { - if (avpicture_deinterlace((AVPicture *)anim->pFrameDeinterlaced, - (const AVPicture *)anim->pFrame, - anim->pCodecCtx->pix_fmt, - anim->pCodecCtx->width, - anim->pCodecCtx->height) < 0) { + if (av_image_deinterlace(anim->pFrameDeinterlaced, + anim->pFrame, + anim->pCodecCtx->pix_fmt, + anim->pCodecCtx->width, + anim->pCodecCtx->height) < 0) { filter_y = true; } else { @@ -808,11 +813,13 @@ static void ffmpeg_postprocess(struct anim *anim) } if (!need_aligned_ffmpeg_buffer(anim)) { - avpicture_fill((AVPicture *)anim->pFrameRGB, - (unsigned char *)ibuf->rect, - AV_PIX_FMT_RGBA, - anim->x, - anim->y); + 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) @@ -903,82 +910,70 @@ static int ffmpeg_decode_video_frame(struct anim *anim) av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n"); - if (anim->next_packet.stream_index == anim->videoStream) { - av_free_packet(&anim->next_packet); - anim->next_packet.stream_index = -1; + if (anim->next_packet->stream_index == anim->videoStream) { + av_packet_unref(anim->next_packet); + anim->next_packet->stream_index = -1; } - while ((rval = av_read_frame(anim->pFormatCtx, &anim->next_packet)) >= 0) { + while ((rval = av_read_frame(anim->pFormatCtx, anim->next_packet)) >= 0) { av_log(anim->pFormatCtx, AV_LOG_DEBUG, "%sREAD: strID=%d (VID: %d) dts=%" PRId64 " pts=%" PRId64 " %s\n", - (anim->next_packet.stream_index == anim->videoStream) ? "->" : " ", - anim->next_packet.stream_index, + (anim->next_packet->stream_index == anim->videoStream) ? "->" : " ", + anim->next_packet->stream_index, anim->videoStream, - (anim->next_packet.dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet.dts, - (anim->next_packet.pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet.pts, - (anim->next_packet.flags & AV_PKT_FLAG_KEY) ? " KEY" : ""); - if (anim->next_packet.stream_index == anim->videoStream) { + (anim->next_packet->dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet->dts, + (anim->next_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->next_packet->pts, + (anim->next_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : ""); + if (anim->next_packet->stream_index == anim->videoStream) { anim->pFrameComplete = 0; - avcodec_decode_video2( - anim->pCodecCtx, anim->pFrame, &anim->pFrameComplete, &anim->next_packet); + avcodec_send_packet(anim->pCodecCtx, anim->next_packet); + anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; if (anim->pFrameComplete) { anim->next_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame); av_log(anim->pFormatCtx, AV_LOG_DEBUG, - " FRAME DONE: next_pts=%" PRId64 " pkt_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", + " FRAME DONE: next_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, - (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pkt_pts, (int64_t)anim->next_pts); break; } } - av_free_packet(&anim->next_packet); - anim->next_packet.stream_index = -1; + av_packet_unref(anim->next_packet); + anim->next_packet->stream_index = -1; } if (rval == AVERROR_EOF) { - /* this sets size and data fields to zero, - * which is necessary to decode the remaining data - * in the decoder engine after EOF. It also prevents a memory - * leak, since av_read_frame spills out a full size packet even - * on EOF... (and: it's safe to call on NULL packets) */ - - av_free_packet(&anim->next_packet); - - anim->next_packet.size = 0; - anim->next_packet.data = 0; - + /* Flush any remaining frames out of the decoder. */ anim->pFrameComplete = 0; - avcodec_decode_video2( - anim->pCodecCtx, anim->pFrame, &anim->pFrameComplete, &anim->next_packet); + avcodec_send_packet(anim->pCodecCtx, NULL); + anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; if (anim->pFrameComplete) { anim->next_pts = av_get_pts_from_frame(anim->pFormatCtx, anim->pFrame); av_log(anim->pFormatCtx, AV_LOG_DEBUG, - " FRAME DONE (after EOF): next_pts=%" PRId64 " pkt_pts=%" PRId64 - ", guessed_pts=%" PRId64 "\n", + " FRAME DONE (after EOF): next_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, - (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pkt_pts, (int64_t)anim->next_pts); rval = 0; } } if (rval < 0) { - anim->next_packet.stream_index = -1; + av_packet_unref(anim->next_packet); + anim->next_packet->stream_index = -1; av_log(anim->pFormatCtx, AV_LOG_ERROR, " DECODE READ FAILED: av_read_frame() " - "returned error: %d\n", - rval); + "returned error: %s\n", + av_err2str(rval)); } return (rval >= 0); @@ -1154,7 +1149,7 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim, int64_t requested_p /* Read first video stream packet. */ AVPacket read_packet = {0}; while (av_read_frame(anim->pFormatCtx, &read_packet) >= 0) { - if (anim->next_packet.stream_index == anim->videoStream) { + if (anim->next_packet->stream_index == anim->videoStream) { break; } } @@ -1246,9 +1241,9 @@ static void ffmpeg_seek_and_decode(struct anim *anim, int position, struct anim_ anim->next_pts = -1; - if (anim->next_packet.stream_index == anim->videoStream) { - av_free_packet(&anim->next_packet); - anim->next_packet.stream_index = -1; + if (anim->next_packet->stream_index == anim->videoStream) { + av_packet_unref(anim->next_packet); + anim->next_packet->stream_index = -1; } /* memset(anim->pFrame, ...) ?? */ @@ -1351,32 +1346,30 @@ static void free_anim_ffmpeg(struct anim *anim) } if (anim->pCodecCtx) { - avcodec_close(anim->pCodecCtx); + avcodec_free_context(&anim->pCodecCtx); avformat_close_input(&anim->pFormatCtx); + av_packet_free(&anim->next_packet); - /* Special case here: pFrame could share pointers with codec, - * so in order to avoid double-free we don't use av_frame_free() - * to free the frame. - * - * Could it be a bug in FFmpeg? - */ - av_free(anim->pFrame); + 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. */ - avpicture_fill((AVPicture *)anim->pFrameRGB, NULL, AV_PIX_FMT_RGBA, anim->x, anim->y); + 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); sws_freeContext(anim->img_convert_ctx); IMB_freeImBuf(anim->last_frame); - if (anim->next_packet.stream_index != -1) { - av_free_packet(&anim->next_packet); - } } anim->duration_in_frames = 0; } diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index ef9f6d861a3..11ce77e3091 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -48,6 +48,7 @@ #ifdef WITH_FFMPEG # include "ffmpeg_compat.h" +# include <libavutil/imgutils.h> #endif static const char magic[] = "BlenMIdx"; @@ -488,14 +489,14 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( rv->of = avformat_alloc_context(); rv->of->oformat = av_guess_format("avi", NULL, NULL); - BLI_strncpy(rv->of->filename, fname, sizeof(rv->of->filename)); + rv->of->url = av_strdup(fname); - fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename); + fprintf(stderr, "Starting work on proxy: %s\n", rv->of->url); rv->st = avformat_new_stream(rv->of, NULL); rv->st->id = 0; - rv->c = rv->st->codec; + rv->c = avcodec_alloc_context3(NULL); rv->c->codec_type = AVMEDIA_TYPE_VIDEO; rv->c->codec_id = AV_CODEC_ID_H264; rv->c->width = width; @@ -513,7 +514,9 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( fprintf(stderr, "No ffmpeg encoder available? " "Proxy not built!\n"); - av_free(rv->of); + avcodec_free_context(&rv->c); + avformat_free_context(rv->of); + MEM_freeN(rv); return NULL; } @@ -524,7 +527,7 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( rv->c->pix_fmt = AV_PIX_FMT_YUVJ420P; } - rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->codec->sample_aspect_ratio; + rv->c->sample_aspect_ratio = rv->st->sample_aspect_ratio = st->sample_aspect_ratio; rv->c->time_base.den = 25; rv->c->time_base.num = 1; @@ -557,34 +560,54 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( } if (rv->of->flags & AVFMT_GLOBALHEADER) { - rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER; + rv->c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } - if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) { + avcodec_parameters_from_context(rv->st->codecpar, rv->c); + + int ret = avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE); + + if (ret < 0) { fprintf(stderr, - "Couldn't open outputfile! " - "Proxy not built!\n"); - av_free(rv->of); - return 0; + "Couldn't open IO: %s\n" + "Proxy not built!\n", + av_err2str(ret)); + avcodec_free_context(&rv->c); + avformat_free_context(rv->of); + MEM_freeN(rv); + return NULL; } - avcodec_open2(rv->c, rv->codec, &codec_opts); + ret = avcodec_open2(rv->c, rv->codec, &codec_opts); + if (ret < 0) { + fprintf(stderr, + "Couldn't open codec: %s\n" + "Proxy not built!\n", + av_err2str(ret)); + avcodec_free_context(&rv->c); + avformat_free_context(rv->of); + MEM_freeN(rv); + return NULL; + } - rv->orig_height = av_get_cropped_height_from_codec(st->codec); + rv->orig_height = st->codecpar->height; - if (st->codec->width != width || st->codec->height != height || - st->codec->pix_fmt != rv->c->pix_fmt) { + if (st->codecpar->width != width || st->codecpar->height != height || + st->codecpar->format != rv->c->pix_fmt) { rv->frame = av_frame_alloc(); - avpicture_fill((AVPicture *)rv->frame, - MEM_mallocN(avpicture_get_size(rv->c->pix_fmt, round_up(width, 16), height), - "alloc proxy output frame"), - rv->c->pix_fmt, - round_up(width, 16), - height); - - rv->sws_ctx = sws_getContext(st->codec->width, + av_image_fill_arrays( + rv->frame->data, + rv->frame->linesize, + MEM_mallocN(av_image_get_buffer_size(rv->c->pix_fmt, round_up(width, 16), height, 1), + "alloc proxy output frame"), + rv->c->pix_fmt, + round_up(width, 16), + height, + 1); + + rv->sws_ctx = sws_getContext(st->codecpar->width, rv->orig_height, - st->codec->pix_fmt, + st->codecpar->format, width, height, rv->c->pix_fmt, @@ -594,26 +617,30 @@ static struct proxy_output_ctx *alloc_proxy_output_ffmpeg( NULL); } - if (avformat_write_header(rv->of, NULL) < 0) { + ret = avformat_write_header(rv->of, NULL); + if (ret < 0) { fprintf(stderr, - "Couldn't set output parameters? " - "Proxy not built!\n"); - av_free(rv->of); - return 0; + "Couldn't write header: %s\n" + "Proxy not built!\n", + av_err2str(ret)); + + if (rv->frame) { + av_frame_free(&rv->frame); + } + + avcodec_free_context(&rv->c); + avformat_free_context(rv->of); + MEM_freeN(rv); + return NULL; } return rv; } -static int add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *frame) +static void add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *frame) { - AVPacket packet = {0}; - int ret, got_output; - - av_init_packet(&packet); - if (!ctx) { - return 0; + return; } if (ctx->sws_ctx && frame && @@ -633,35 +660,46 @@ static int add_to_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, AVFrame *fra frame->pts = ctx->cfra++; } - ret = avcodec_encode_video2(ctx->c, &packet, frame, &got_output); + int ret = avcodec_send_frame(ctx->c, frame); if (ret < 0) { - fprintf(stderr, "Error encoding proxy frame %d for '%s'\n", ctx->cfra - 1, ctx->of->filename); - return 0; + /* Can't send frame to encoder. This shouldn't happen. */ + fprintf(stderr, "Can't send video frame: %s\n", av_err2str(ret)); + return; } + AVPacket *packet = av_packet_alloc(); + + while (ret >= 0) { + ret = avcodec_receive_packet(ctx->c, packet); - if (got_output) { - if (packet.pts != AV_NOPTS_VALUE) { - packet.pts = av_rescale_q(packet.pts, ctx->c->time_base, ctx->st->time_base); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + /* No more packets to flush. */ + break; } - if (packet.dts != AV_NOPTS_VALUE) { - packet.dts = av_rescale_q(packet.dts, ctx->c->time_base, ctx->st->time_base); + if (ret < 0) { + fprintf(stderr, + "Error encoding proxy frame %d for '%s': %s\n", + ctx->cfra - 1, + ctx->of->url, + av_err2str(ret)); + break; } - packet.stream_index = ctx->st->index; + packet->stream_index = ctx->st->index; + av_packet_rescale_ts(packet, ctx->c->time_base, ctx->st->time_base); - if (av_interleaved_write_frame(ctx->of, &packet) != 0) { + int write_ret = av_interleaved_write_frame(ctx->of, packet); + if (write_ret != 0) { fprintf(stderr, "Error writing proxy frame %d " - "into '%s'\n", + "into '%s': %s\n", ctx->cfra - 1, - ctx->of->filename); - return 0; + ctx->of->url, + av_err2str(write_ret)); + break; } - - return 1; } - return 0; + av_packet_free(&packet); } static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback) @@ -674,15 +712,15 @@ static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback) } if (!rollback) { - while (add_to_proxy_output_ffmpeg(ctx, NULL)) { - } + /* Flush the remaining packets. */ + add_to_proxy_output_ffmpeg(ctx, NULL); } avcodec_flush_buffers(ctx->c); av_write_trailer(ctx->of); - avcodec_close(ctx->c); + avcodec_free_context(&ctx->c); if (ctx->of->oformat) { if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) { @@ -777,7 +815,7 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, /* Find the video stream */ context->videoStream = -1; for (i = 0; i < context->iFormatCtx->nb_streams; i++) { - if (context->iFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (context->iFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (streamcount > 0) { streamcount--; continue; @@ -794,9 +832,8 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, } context->iStream = context->iFormatCtx->streams[context->videoStream]; - context->iCodecCtx = context->iStream->codec; - context->iCodec = avcodec_find_decoder(context->iCodecCtx->codec_id); + context->iCodec = avcodec_find_decoder(context->iStream->codecpar->codec_id); if (context->iCodec == NULL) { avformat_close_input(&context->iFormatCtx); @@ -804,7 +841,9 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, return NULL; } - context->iCodecCtx->workaround_bugs = 1; + context->iCodecCtx = avcodec_alloc_context3(NULL); + avcodec_parameters_to_context(context->iCodecCtx, context->iStream->codecpar); + context->iCodecCtx->workaround_bugs = FF_BUG_AUTODETECT; if (context->iCodec->capabilities & AV_CODEC_CAP_AUTO_THREADS) { context->iCodecCtx->thread_count = 0; @@ -822,19 +861,19 @@ static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, if (avcodec_open2(context->iCodecCtx, context->iCodec, NULL) < 0) { avformat_close_input(&context->iFormatCtx); + avcodec_free_context(&context->iCodecCtx); MEM_freeN(context); return NULL; } for (i = 0; i < num_proxy_sizes; i++) { if (proxy_sizes_in_use & proxy_sizes[i]) { - context->proxy_ctx[i] = alloc_proxy_output_ffmpeg( - anim, - context->iStream, - proxy_sizes[i], - context->iCodecCtx->width * proxy_fac[i], - av_get_cropped_height_from_codec(context->iCodecCtx) * proxy_fac[i], - quality); + context->proxy_ctx[i] = alloc_proxy_output_ffmpeg(anim, + context->iStream, + proxy_sizes[i], + context->iCodecCtx->width * proxy_fac[i], + context->iCodecCtx->height * proxy_fac[i], + quality); if (!context->proxy_ctx[i]) { proxy_sizes_in_use &= ~proxy_sizes[i]; } @@ -873,7 +912,7 @@ static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int } } - avcodec_close(context->iCodecCtx); + avcodec_free_context(&context->iCodecCtx); avformat_close_input(&context->iFormatCtx); MEM_freeN(context); @@ -938,23 +977,18 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context, short *do_update, float *progress) { - AVFrame *in_frame = 0; - AVPacket next_packet; + AVFrame *in_frame = av_frame_alloc(); + AVPacket *next_packet = av_packet_alloc(); uint64_t stream_size; - memset(&next_packet, 0, sizeof(AVPacket)); - - in_frame = av_frame_alloc(); - stream_size = avio_size(context->iFormatCtx->pb); context->frame_rate = av_q2d(av_guess_frame_rate(context->iFormatCtx, context->iStream, NULL)); context->pts_time_base = av_q2d(context->iStream->time_base); - while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) { - int frame_finished = 0; + while (av_read_frame(context->iFormatCtx, next_packet) >= 0) { float next_progress = - (float)((int)floor(((double)next_packet.pos) * 100 / ((double)stream_size) + 0.5)) / 100; + (float)((int)floor(((double)next_packet->pos) * 100 / ((double)stream_size) + 0.5)) / 100; if (*progress != next_progress) { *progress = next_progress; @@ -962,50 +996,59 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context, } if (*stop) { - av_free_packet(&next_packet); break; } - if (next_packet.stream_index == context->videoStream) { - if (next_packet.flags & AV_PKT_FLAG_KEY) { + if (next_packet->stream_index == context->videoStream) { + if (next_packet->flags & AV_PKT_FLAG_KEY) { context->last_seek_pos = context->seek_pos; context->last_seek_pos_dts = context->seek_pos_dts; - context->seek_pos = next_packet.pos; - context->seek_pos_dts = next_packet.dts; - context->seek_pos_pts = next_packet.pts; + context->seek_pos = next_packet->pos; + context->seek_pos_dts = next_packet->dts; + context->seek_pos_pts = next_packet->pts; } - avcodec_decode_video2(context->iCodecCtx, in_frame, &frame_finished, &next_packet); - } + int ret = avcodec_send_packet(context->iCodecCtx, next_packet); + while (ret >= 0) { + ret = avcodec_receive_frame(context->iCodecCtx, in_frame); - if (frame_finished) { - index_rebuild_ffmpeg_proc_decoded_frame(context, &next_packet, in_frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + /* No more frames to flush. */ + break; + } + if (ret < 0) { + fprintf(stderr, "Error decoding proxy frame: %s\n", av_err2str(ret)); + break; + } + index_rebuild_ffmpeg_proc_decoded_frame(context, next_packet, in_frame); + } } - av_free_packet(&next_packet); } /* process pictures still stuck in decoder engine after EOF - * according to ffmpeg docs using 0-size packets. + * according to ffmpeg docs using NULL packets. * * At least, if we haven't already stopped... */ - /* this creates the 0-size packet and prevents a memory leak. */ - av_free_packet(&next_packet); - if (!*stop) { - int frame_finished; - - do { - frame_finished = 0; + int ret = avcodec_send_packet(context->iCodecCtx, NULL); - avcodec_decode_video2(context->iCodecCtx, in_frame, &frame_finished, &next_packet); + while (ret >= 0) { + ret = avcodec_receive_frame(context->iCodecCtx, in_frame); - if (frame_finished) { - index_rebuild_ffmpeg_proc_decoded_frame(context, &next_packet, in_frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + /* No more frames to flush. */ + break; } - } while (frame_finished); + if (ret < 0) { + fprintf(stderr, "Error flushing proxy frame: %s\n", av_err2str(ret)); + break; + } + index_rebuild_ffmpeg_proc_decoded_frame(context, next_packet, in_frame); + } } + av_packet_free(&next_packet); av_free(in_frame); return 1; diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 64dad5de902..fabf6c5c3bd 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -245,7 +245,6 @@ static void ffmpeg_log_callback(void *ptr, int level, const char *format, va_lis void IMB_ffmpeg_init(void) { - av_register_all(); avdevice_register_all(); ffmpeg_last_error[0] = '\0'; @@ -269,7 +268,6 @@ static int isffmpeg(const char *filepath) unsigned int i; int videoStream; AVCodec *pCodec; - AVCodecContext *pCodecCtx; if (BLI_path_extension_check_n(filepath, ".swf", @@ -310,8 +308,8 @@ static int isffmpeg(const char *filepath) /* Find the first video stream */ videoStream = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) { - if (pFormatCtx->streams[i] && pFormatCtx->streams[i]->codec && - (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)) { + if (pFormatCtx->streams[i] && pFormatCtx->streams[i]->codecpar && + (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)) { videoStream = i; break; } @@ -322,21 +320,15 @@ static int isffmpeg(const char *filepath) return 0; } - pCodecCtx = pFormatCtx->streams[videoStream]->codec; + AVCodecParameters *codec_par = pFormatCtx->streams[videoStream]->codecpar; /* Find the decoder for the video stream */ - pCodec = avcodec_find_decoder(pCodecCtx->codec_id); + pCodec = avcodec_find_decoder(codec_par->codec_id); if (pCodec == NULL) { avformat_close_input(&pFormatCtx); return 0; } - if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { - avformat_close_input(&pFormatCtx); - return 0; - } - - avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); return 1; |