static void free_proxy_output_ffmpeg(struct proxy_output_ctx *ctx, int rollback) { char fname[FILE_MAX]; char fname_tmp[FILE_MAX]; if (!ctx) { return; } if (!rollback) { while (add_to_proxy_output_ffmpeg(ctx, NULL)) {} } avcodec_flush_buffers(ctx->c); av_write_trailer(ctx->of); avcodec_close(ctx->c); if (ctx->of->oformat) { if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) { avio_close(ctx->of->pb); } } avformat_free_context(ctx->of); if (ctx->sws_ctx) { sws_freeContext(ctx->sws_ctx); MEM_freeN(ctx->frame->data[0]); av_free(ctx->frame); } get_proxy_filename(ctx->anim, ctx->proxy_size, fname_tmp, true); if (rollback) { unlink(fname_tmp); } else { get_proxy_filename(ctx->anim, ctx->proxy_size, fname, false); unlink(fname); BLI_rename(fname_tmp, fname); } MEM_freeN(ctx); }
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; in_frame = avcodec_alloc_frame(); 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); while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) { int frame_finished = 0; float next_progress = (float)((int)floor(((double) next_packet.pos) * 100 / ((double) stream_size) + 0.5)) / 100; if (*progress != next_progress) { *progress = next_progress; *do_update = TRUE; } if (*stop) { av_free_packet(&next_packet); break; } 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; } avcodec_decode_video2( context->iCodecCtx, in_frame, &frame_finished, &next_packet); } 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; } frameno = floor((pts - start_pts) * pts_time_base * 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 < seek_pos_pts) { s_pos = last_seek_pos; s_dts = last_seek_pos_dts; } for (i = 0; i < context->num_indexers; i++) { if (context->tcs_in_use & tc_types[i]) { int tc_frameno = frameno; if (tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS) tc_frameno = frameno_gapless; IMB_index_builder_proc_frame( context->indexer[i], next_packet.data, next_packet.size, tc_frameno, s_pos, s_dts, pts); } } frameno_gapless++; } av_free_packet(&next_packet); } av_free(in_frame); return 1; }
static int index_rebuild_ffmpeg(struct anim * anim, IMB_Timecode_Type tcs_in_use, IMB_Proxy_Size proxy_sizes_in_use, int quality, short *stop, short *do_update, float *progress) { int i, videoStream; 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; int start_pts_set = FALSE; AVFormatContext *iFormatCtx; AVCodecContext *iCodecCtx; AVCodec *iCodec; AVStream *iStream; AVFrame* in_frame = 0; AVPacket next_packet; int streamcount; struct proxy_output_ctx * proxy_ctx[IMB_PROXY_MAX_SLOT]; anim_index_builder * indexer [IMB_TC_MAX_SLOT]; int num_proxy_sizes = IMB_PROXY_MAX_SLOT; int num_indexers = IMB_TC_MAX_SLOT; uint64_t stream_size; memset(proxy_ctx, 0, sizeof(proxy_ctx)); memset(indexer, 0, sizeof(indexer)); if(av_open_input_file(&iFormatCtx, anim->name, NULL, 0, NULL) != 0) { return 0; } if (av_find_stream_info(iFormatCtx) < 0) { av_close_input_file(iFormatCtx); return 0; } streamcount = anim->streamindex; /* Find the video stream */ videoStream = -1; for (i = 0; i < iFormatCtx->nb_streams; i++) if(iFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { if (streamcount > 0) { streamcount--; continue; } videoStream = i; break; } if (videoStream == -1) { av_close_input_file(iFormatCtx); return 0; } iStream = iFormatCtx->streams[videoStream]; iCodecCtx = iStream->codec; iCodec = avcodec_find_decoder(iCodecCtx->codec_id); if (iCodec == NULL) { av_close_input_file(iFormatCtx); return 0; } iCodecCtx->workaround_bugs = 1; if (avcodec_open(iCodecCtx, iCodec) < 0) { av_close_input_file(iFormatCtx); return 0; } in_frame = avcodec_alloc_frame(); stream_size = avio_size(iFormatCtx->pb); for (i = 0; i < num_proxy_sizes; i++) { if (proxy_sizes_in_use & proxy_sizes[i]) { proxy_ctx[i] = alloc_proxy_output_ffmpeg( anim, iStream, proxy_sizes[i], iCodecCtx->width * proxy_fac[i], iCodecCtx->height * proxy_fac[i], quality); if (!proxy_ctx[i]) { proxy_sizes_in_use &= ~proxy_sizes[i]; } } } for (i = 0; i < num_indexers; i++) { if (tcs_in_use & tc_types[i]) { char fname[FILE_MAXDIR+FILE_MAXFILE]; get_tc_filename(anim, tc_types[i], fname); indexer[i] = IMB_index_builder_create(fname); if (!indexer[i]) { tcs_in_use &= ~tc_types[i]; } } } frame_rate = av_q2d(iStream->r_frame_rate); pts_time_base = av_q2d(iStream->time_base); while(av_read_frame(iFormatCtx, &next_packet) >= 0) { int frame_finished = 0; float next_progress = ((int)floor(((double) next_packet.pos) * 100 / ((double) stream_size)+0.5)) / 100; if (*progress != next_progress) { *progress = next_progress; *do_update = 1; } if (*stop) { av_free_packet(&next_packet); break; } if (next_packet.stream_index == 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; } avcodec_decode_video2( iCodecCtx, in_frame, &frame_finished, &next_packet); } 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(iFormatCtx, in_frame); for (i = 0; i < num_proxy_sizes; i++) { add_to_proxy_output_ffmpeg( proxy_ctx[i], in_frame); } if (!start_pts_set) { start_pts = pts; start_pts_set = TRUE; } frameno = (pts - start_pts) * pts_time_base * frame_rate; /* 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 < seek_pos_pts) { s_pos = last_seek_pos; s_dts = last_seek_pos_dts; } for (i = 0; i < num_indexers; i++) { if (tcs_in_use & tc_types[i]) { IMB_index_builder_proc_frame( indexer[i], next_packet.data, next_packet.size, frameno, s_pos, s_dts, pts); } } } av_free_packet(&next_packet); } for (i = 0; i < num_indexers; i++) { if (tcs_in_use & tc_types[i]) { IMB_index_builder_finish(indexer[i], *stop); } } for (i = 0; i < num_proxy_sizes; i++) { if (proxy_sizes_in_use & proxy_sizes[i]) { free_proxy_output_ffmpeg(proxy_ctx[i], *stop); } } av_free(in_frame); return 1; }