Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Schlaile <peter@schlaile.de>2012-09-08 01:41:38 +0400
committerPeter Schlaile <peter@schlaile.de>2012-09-08 01:41:38 +0400
commitc95d4f68b863c851d0b8bddef8092fdc0932610e (patch)
treec3d0647274aa50776a32707dd50c53636ee7112b /source/blender/imbuf/intern/indexer.c
parentd6a68ea850974a271dfd4c83a64d36ba763babf8 (diff)
== FFMPEG ==
This fixes [#32399] VSE doesn't show last 3 frames of Quicktime movie. Some decoders store frames internally until EOF. So one has to feed the decoding engine with empty packets after EOF until all frames could be extracted properly.
Diffstat (limited to 'source/blender/imbuf/intern/indexer.c')
-rw-r--r--source/blender/imbuf/intern/indexer.c152
1 files changed, 93 insertions, 59 deletions
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 458f0198aed..ea493e277f3 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -723,6 +723,17 @@ typedef struct FFmpegIndexBuilderContext {
IMB_Timecode_Type tcs_in_use;
IMB_Proxy_Size proxy_sizes_in_use;
+
+ unsigned long long seek_pos;
+ unsigned long long last_seek_pos;
+ unsigned long long seek_pos_dts;
+ unsigned long long seek_pos_pts;
+ unsigned long long last_seek_pos_dts;
+ unsigned long long start_pts;
+ double frame_rate;
+ double pts_time_base;
+ int frameno, frameno_gapless;
+ int start_pts_set;
} FFmpegIndexBuilderContext;
static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
@@ -839,20 +850,63 @@ static void index_rebuild_ffmpeg_finish(FFmpegIndexBuilderContext *context, int
MEM_freeN(context);
}
+static void index_rebuild_ffmpeg_proc_decoded_frame(
+ FFmpegIndexBuilderContext *context,
+ AVPacket * curr_packet,
+ AVFrame *in_frame)
+{
+ int i;
+ unsigned long long s_pos = context->seek_pos;
+ unsigned long long s_dts = context->seek_pos_dts;
+ unsigned long long pts = av_get_pts_from_frame(context->iFormatCtx, in_frame);
+
+ for (i = 0; i < context->num_proxy_sizes; i++) {
+ add_to_proxy_output_ffmpeg(context->proxy_ctx[i], in_frame);
+ }
+
+ if (!context->start_pts_set) {
+ context->start_pts = pts;
+ context->start_pts_set = TRUE;
+ }
+
+ context->frameno = floor((pts - context->start_pts)
+ * context->pts_time_base
+ * context->frame_rate + 0.5f);
+
+ /* decoding starts *always* on I-Frames,
+ * so: P-Frames won't work, even if all the
+ * information is in place, when we seek
+ * to the I-Frame presented *after* the P-Frame,
+ * but located before the P-Frame within
+ * the stream */
+
+ if (pts < context->seek_pos_pts) {
+ s_pos = context->last_seek_pos;
+ s_dts = context->last_seek_pos_dts;
+ }
+
+ for (i = 0; i < context->num_indexers; i++) {
+ if (context->tcs_in_use & tc_types[i]) {
+ int tc_frameno = context->frameno;
+
+ if (tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS)
+ tc_frameno = context->frameno_gapless;
+
+ IMB_index_builder_proc_frame(
+ context->indexer[i],
+ curr_packet->data,
+ curr_packet->size,
+ tc_frameno,
+ s_pos, s_dts, pts);
+ }
+ }
+
+ context->frameno_gapless++;
+}
+
static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
short *stop, short *do_update, float *progress)
{
- int i;
- unsigned long long seek_pos = 0;
- unsigned long long last_seek_pos = 0;
- unsigned long long seek_pos_dts = 0;
- unsigned long long seek_pos_pts = 0;
- unsigned long long last_seek_pos_dts = 0;
- unsigned long long start_pts = 0;
- double frame_rate;
- double pts_time_base;
- int frameno = 0, frameno_gapless = 0;
- int start_pts_set = FALSE;
AVFrame *in_frame = 0;
AVPacket next_packet;
uint64_t stream_size;
@@ -861,8 +915,8 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
stream_size = avio_size(context->iFormatCtx->pb);
- frame_rate = av_q2d(context->iStream->r_frame_rate);
- pts_time_base = av_q2d(context->iStream->time_base);
+ context->frame_rate = av_q2d(context->iStream->r_frame_rate);
+ context->pts_time_base = av_q2d(context->iStream->time_base);
while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
int frame_finished = 0;
@@ -881,11 +935,11 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
if (next_packet.stream_index == context->videoStream) {
if (next_packet.flags & AV_PKT_FLAG_KEY) {
- last_seek_pos = seek_pos;
- last_seek_pos_dts = seek_pos_dts;
- seek_pos = next_packet.pos;
- seek_pos_dts = next_packet.dts;
- seek_pos_pts = next_packet.pts;
+ 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;
}
avcodec_decode_video2(
@@ -894,54 +948,34 @@ static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
}
if (frame_finished) {
- unsigned long long s_pos = seek_pos;
- unsigned long long s_dts = seek_pos_dts;
- unsigned long long pts = av_get_pts_from_frame(context->iFormatCtx, in_frame);
-
- for (i = 0; i < context->num_proxy_sizes; i++) {
- add_to_proxy_output_ffmpeg(
- context->proxy_ctx[i], in_frame);
- }
-
- if (!start_pts_set) {
- start_pts = pts;
- start_pts_set = TRUE;
- }
+ index_rebuild_ffmpeg_proc_decoded_frame(
+ context, &next_packet, in_frame);
+ }
+ av_free_packet(&next_packet);
+ }
- frameno = floor((pts - start_pts) *
- pts_time_base * frame_rate + 0.5f);
+ /* process pictures still stuck in decoder engine after EOF
+ according to ffmpeg docs using 0-size packets.
- /* decoding starts *always* on I-Frames,
- * so: P-Frames won't work, even if all the
- * information is in place, when we seek
- * to the I-Frame presented *after* the P-Frame,
- * but located before the P-Frame within
- * the stream */
+ At least, if we haven't already stopped... */
+ if (!*stop) {
+ int frame_finished;
- if (pts < seek_pos_pts) {
- s_pos = last_seek_pos;
- s_dts = last_seek_pos_dts;
- }
+ next_packet.size = 0;
+ next_packet.data = 0;
- for (i = 0; i < context->num_indexers; i++) {
- if (context->tcs_in_use & tc_types[i]) {
- int tc_frameno = frameno;
+ do {
+ frame_finished = 0;
- if (tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS)
- tc_frameno = frameno_gapless;
+ avcodec_decode_video2(
+ context->iCodecCtx, in_frame, &frame_finished,
+ &next_packet);
- IMB_index_builder_proc_frame(
- context->indexer[i],
- next_packet.data,
- next_packet.size,
- tc_frameno,
- s_pos, s_dts, pts);
- }
+ if (frame_finished) {
+ index_rebuild_ffmpeg_proc_decoded_frame(
+ context, &next_packet, in_frame);
}
-
- frameno_gapless++;
- }
- av_free_packet(&next_packet);
+ } while (frame_finished);
}
av_free(in_frame);