Beispiel #1
0
static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
                                                      IMB_Proxy_Size proxy_sizes_in_use, int quality)
{
	FFmpegIndexBuilderContext *context = MEM_callocN(sizeof(FFmpegIndexBuilderContext), "FFmpeg index builder context");
	int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
	int num_indexers = IMB_TC_MAX_SLOT;
	int i, streamcount;

	context->tcs_in_use = tcs_in_use;
	context->proxy_sizes_in_use = proxy_sizes_in_use;
	context->num_proxy_sizes = IMB_PROXY_MAX_SLOT;
	context->num_indexers = IMB_TC_MAX_SLOT;

	memset(context->proxy_ctx, 0, sizeof(context->proxy_ctx));
	memset(context->indexer, 0, sizeof(context->indexer));

	if (avformat_open_input(&context->iFormatCtx, anim->name, NULL, NULL) != 0) {
		MEM_freeN(context);
		return NULL;
	}

	if (avformat_find_stream_info(context->iFormatCtx, NULL) < 0) {
		avformat_close_input(&context->iFormatCtx);
		MEM_freeN(context);
		return NULL;
	}

	streamcount = anim->streamindex;

	/* 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 (streamcount > 0) {
				streamcount--;
				continue;
			}
			context->videoStream = i;
			break;
		}

	if (context->videoStream == -1) {
		avformat_close_input(&context->iFormatCtx);
		MEM_freeN(context);
		return NULL;
	}

	context->iStream = context->iFormatCtx->streams[context->videoStream];
	context->iCodecCtx = context->iStream->codec;

	context->iCodec = avcodec_find_decoder(context->iCodecCtx->codec_id);

	if (context->iCodec == NULL) {
		avformat_close_input(&context->iFormatCtx);
		MEM_freeN(context);
		return NULL;
	}

	context->iCodecCtx->workaround_bugs = 1;

	if (avcodec_open2(context->iCodecCtx, context->iCodec, NULL) < 0) {
		avformat_close_input(&context->iFormatCtx);
		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);
			if (!context->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_MAX];

			get_tc_filename(anim, tc_types[i], fname);

			context->indexer[i] = IMB_index_builder_create(fname);
			if (!context->indexer[i]) {
				tcs_in_use &= ~tc_types[i];
			}
		}
	}

	return (IndexBuildContext *)context;
}
Beispiel #2
0
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;
}