Changeset View
Changeset View
Standalone View
Standalone View
source/blender/imbuf/intern/anim_movie.c
| Show First 20 Lines • Show All 933 Lines • ▼ Show 20 Lines | if (need_aligned_ffmpeg_buffer(anim)) { | ||||
| } | } | ||||
| } | } | ||||
| if (filter_y) { | if (filter_y) { | ||||
| IMB_filtery(ibuf); | IMB_filtery(ibuf); | ||||
| } | } | ||||
| } | } | ||||
| /* decode one video frame also considering the packet read into cur_packet */ | void ffmpeg_frame_queue_push(struct anim *anim, AVFrame *frame) | ||||
| { | |||||
| LinkData *link = BLI_genericNodeN(frame); | |||||
| BLI_addtail(&anim->frame_queue, link); | |||||
| } | |||||
| static int ffmpeg_decode_video_frame(struct anim *anim) | AVFrame *ffmpeg_frame_queue_pop(struct anim *anim) | ||||
| { | { | ||||
| int rval = 0; | LinkData *link = BLI_pophead(&anim->frame_queue); | ||||
| AVFrame *frame = link->data; | |||||
| MEM_freeN(link); | |||||
| return frame; | |||||
| } | |||||
| static void ffmpeg_frame_queue_free(struct anim *anim) | |||||
| { | |||||
| while (!BLI_listbase_is_empty(&anim->frame_queue)) { | |||||
| AVFrame *frame = ffmpeg_frame_queue_pop(anim); | |||||
| av_frame_free(&frame); | |||||
| } | |||||
| } | |||||
| /* If decoder outputs more than 1 frame, store them in `anim->frame_queue`. */ | |||||
| static void ffmpeg_frame_queue_fill(struct anim *anim) | |||||
| { | |||||
| AVFrame *frame; | |||||
| int ret = 0; | |||||
| while (ret >= 0 && !(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)) { | |||||
| frame = av_frame_alloc(); | |||||
| ret = avcodec_receive_frame(anim->pCodecCtx, frame); | |||||
| if (ret == 0) { | |||||
| ffmpeg_frame_queue_push(anim, frame); | |||||
| } | |||||
| } | |||||
| /* Last frame is always empty, it must be freed. */ | |||||
| av_frame_free(&frame); | |||||
| return; | |||||
| } | |||||
| static void ffmpeg_decode_store_frame_pts(struct anim *anim) | |||||
| { | |||||
| anim->cur_pts = av_get_pts_from_frame(anim->pFrame); | |||||
| if (anim->pFrame->key_frame) { | |||||
| anim->cur_key_frame_pts = anim->cur_pts; | |||||
| } | |||||
| av_log(anim->pFormatCtx, | |||||
| AV_LOG_DEBUG, | |||||
| " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", | |||||
| (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, | |||||
| (int64_t)anim->cur_pts); | |||||
| } | |||||
| /* decode one video frame also considering the packet read into cur_packet */ | |||||
| static int ffmpeg_decode_video_frame(struct anim *anim) | |||||
| { | |||||
| av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n"); | av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE VIDEO FRAME\n"); | ||||
| /* Use Frame from queue if available. */ | |||||
| if (!BLI_listbase_is_empty(&anim->frame_queue)) { | |||||
| av_log(anim->pFormatCtx, AV_LOG_DEBUG, " USE QUEUE\n"); | |||||
| av_frame_free(&anim->pFrame); | |||||
| anim->pFrame = ffmpeg_frame_queue_pop(anim); | |||||
| ffmpeg_decode_store_frame_pts(anim); | |||||
| return 1; | |||||
| } | |||||
| int rval = 0; | |||||
| if (anim->cur_packet->stream_index == anim->videoStream) { | if (anim->cur_packet->stream_index == anim->videoStream) { | ||||
| av_packet_unref(anim->cur_packet); | av_packet_unref(anim->cur_packet); | ||||
| anim->cur_packet->stream_index = -1; | anim->cur_packet->stream_index = -1; | ||||
| } | } | ||||
| while ((rval = av_read_frame(anim->pFormatCtx, anim->cur_packet)) >= 0) { | while ((rval = av_read_frame(anim->pFormatCtx, anim->cur_packet)) >= 0) { | ||||
| av_log(anim->pFormatCtx, | av_log(anim->pFormatCtx, | ||||
| AV_LOG_DEBUG, | AV_LOG_DEBUG, | ||||
| "%sREAD: strID=%d (VID: %d) dts=%" PRId64 " pts=%" PRId64 " %s\n", | "%sREAD: strID=%d (VID: %d) dts=%" PRId64 " pts=%" PRId64 " %s\n", | ||||
| (anim->cur_packet->stream_index == anim->videoStream) ? "->" : " ", | (anim->cur_packet->stream_index == anim->videoStream) ? "->" : " ", | ||||
| anim->cur_packet->stream_index, | anim->cur_packet->stream_index, | ||||
| anim->videoStream, | anim->videoStream, | ||||
| (anim->cur_packet->dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->dts, | (anim->cur_packet->dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->dts, | ||||
| (anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->pts, | (anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->pts, | ||||
| (anim->cur_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : ""); | (anim->cur_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : ""); | ||||
| if (anim->cur_packet->stream_index == anim->videoStream) { | if (anim->cur_packet->stream_index == anim->videoStream) { | ||||
| anim->pFrameComplete = 0; | anim->pFrameComplete = 0; | ||||
| avcodec_send_packet(anim->pCodecCtx, anim->cur_packet); | avcodec_send_packet(anim->pCodecCtx, anim->cur_packet); | ||||
| anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; | anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; | ||||
| if (anim->pFrameComplete) { | if (anim->pFrameComplete) { | ||||
| anim->cur_pts = av_get_pts_from_frame(anim->pFrame); | ffmpeg_frame_queue_fill(anim); | ||||
| ffmpeg_decode_store_frame_pts(anim); | |||||
| if (anim->pFrame->key_frame) { | |||||
| anim->cur_key_frame_pts = anim->cur_pts; | |||||
| } | |||||
| av_log(anim->pFormatCtx, | |||||
| AV_LOG_DEBUG, | |||||
| " FRAME DONE: cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", | |||||
| (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, | |||||
| (int64_t)anim->cur_pts); | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| av_packet_unref(anim->cur_packet); | av_packet_unref(anim->cur_packet); | ||||
| anim->cur_packet->stream_index = -1; | anim->cur_packet->stream_index = -1; | ||||
| } | } | ||||
| if (rval == AVERROR_EOF) { | if (rval == AVERROR_EOF) { | ||||
| /* Flush any remaining frames out of the decoder. */ | /* Flush any remaining frames out of the decoder. */ | ||||
| anim->pFrameComplete = 0; | anim->pFrameComplete = 0; | ||||
| avcodec_send_packet(anim->pCodecCtx, NULL); | avcodec_send_packet(anim->pCodecCtx, NULL); | ||||
| anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; | anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0; | ||||
| if (anim->pFrameComplete) { | if (anim->pFrameComplete) { | ||||
| anim->cur_pts = av_get_pts_from_frame(anim->pFrame); | ffmpeg_frame_queue_fill(anim); | ||||
| ffmpeg_decode_store_frame_pts(anim); | |||||
| if (anim->pFrame->key_frame) { | |||||
| anim->cur_key_frame_pts = anim->cur_pts; | |||||
| } | |||||
| av_log(anim->pFormatCtx, | |||||
| AV_LOG_DEBUG, | |||||
| " FRAME DONE (after EOF): cur_pts=%" PRId64 ", guessed_pts=%" PRId64 "\n", | |||||
| (anim->pFrame->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->pFrame->pts, | |||||
| (int64_t)anim->cur_pts); | |||||
| rval = 0; | rval = 0; | ||||
| } | } | ||||
| } | } | ||||
| if (rval < 0) { | if (rval < 0) { | ||||
| av_packet_unref(anim->cur_packet); | av_packet_unref(anim->cur_packet); | ||||
| anim->cur_packet->stream_index = -1; | anim->cur_packet->stream_index = -1; | ||||
| ▲ Show 20 Lines • Show All 350 Lines • ▼ Show 20 Lines | av_log(anim->pFormatCtx, | ||||
| pos, | pos, | ||||
| position, | position, | ||||
| pts_to_search, | pts_to_search, | ||||
| ret); | ret); | ||||
| } | } | ||||
| /* Flush the internal buffers of ffmpeg. This needs to be done after seeking to avoid decoding | /* Flush the internal buffers of ffmpeg. This needs to be done after seeking to avoid decoding | ||||
| * errors. */ | * errors. */ | ||||
| avcodec_flush_buffers(anim->pCodecCtx); | avcodec_flush_buffers(anim->pCodecCtx); | ||||
| if (!BLI_listbase_is_empty(&anim->frame_queue)) { | |||||
| ffmpeg_frame_queue_free(anim); | |||||
| } | |||||
| anim->cur_pts = -1; | anim->cur_pts = -1; | ||||
| if (anim->cur_packet->stream_index == anim->videoStream) { | if (anim->cur_packet->stream_index == anim->videoStream) { | ||||
| av_packet_unref(anim->cur_packet); | av_packet_unref(anim->cur_packet); | ||||
| anim->cur_packet->stream_index = -1; | anim->cur_packet->stream_index = -1; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | static void free_anim_ffmpeg(struct anim *anim) | ||||
| } | } | ||||
| if (anim->pCodecCtx) { | if (anim->pCodecCtx) { | ||||
| avcodec_free_context(&anim->pCodecCtx); | avcodec_free_context(&anim->pCodecCtx); | ||||
| avformat_close_input(&anim->pFormatCtx); | avformat_close_input(&anim->pFormatCtx); | ||||
| av_packet_free(&anim->cur_packet); | av_packet_free(&anim->cur_packet); | ||||
| av_frame_free(&anim->pFrame); | av_frame_free(&anim->pFrame); | ||||
| ffmpeg_frame_queue_free(anim); | |||||
| if (!need_aligned_ffmpeg_buffer(anim)) { | if (!need_aligned_ffmpeg_buffer(anim)) { | ||||
| /* If there's no need for own aligned buffer it means that FFmpeg's | /* 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 | * frame shares the same buffer as temporary ImBuf. In this case we | ||||
| * should not free the buffer when freeing the FFmpeg buffer. | * should not free the buffer when freeing the FFmpeg buffer. | ||||
| */ | */ | ||||
| av_image_fill_arrays(anim->pFrameRGB->data, | av_image_fill_arrays(anim->pFrameRGB->data, | ||||
| anim->pFrameRGB->linesize, | anim->pFrameRGB->linesize, | ||||
| ▲ Show 20 Lines • Show All 241 Lines • Show Last 20 Lines | |||||