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:
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);