Esempio n. 1
0
int VideoFFmpeg::openStream(const char *filename, AVInputFormat *inputFormat, AVDictionary **formatParams)
{
	AVFormatContext *formatCtx = NULL;
	int				i, videoStream;
	AVCodec			*codec;
	AVCodecContext	*codecCtx;

	if (avformat_open_input(&formatCtx, filename, inputFormat, formatParams)!=0)
		return -1;

	if (avformat_find_stream_info(formatCtx, NULL) < 0)
	{
		avformat_close_input(&formatCtx);
		return -1;
	}

	/* Find the first video stream */
	videoStream=-1;
	for (i=0; i<formatCtx->nb_streams; i++)
	{
		if (formatCtx->streams[i] &&
			get_codec_from_stream(formatCtx->streams[i]) &&
			(get_codec_from_stream(formatCtx->streams[i])->codec_type==AVMEDIA_TYPE_VIDEO))
		{
			videoStream=i;
			break;
		}
	}

	if (videoStream==-1)
	{
		avformat_close_input(&formatCtx);
		return -1;
	}

	codecCtx = get_codec_from_stream(formatCtx->streams[videoStream]);

	/* Find the decoder for the video stream */
	codec=avcodec_find_decoder(codecCtx->codec_id);
	if (codec==NULL)
	{
		avformat_close_input(&formatCtx);
		return -1;
	}
	codecCtx->workaround_bugs = 1;
	if (avcodec_open2(codecCtx, codec, NULL) < 0)
	{
		avformat_close_input(&formatCtx);
		return -1;
	}

#ifdef FFMPEG_OLD_FRAME_RATE
	if (codecCtx->frame_rate>1000 && codecCtx->frame_rate_base==1)
		codecCtx->frame_rate_base=1000;
	m_baseFrameRate = (double)codecCtx->frame_rate / (double)codecCtx->frame_rate_base;
#else
	m_baseFrameRate = av_q2d(av_get_r_frame_rate_compat(formatCtx, formatCtx->streams[videoStream]));
#endif
	if (m_baseFrameRate <= 0.0)
		m_baseFrameRate = defFrameRate;

	m_codec = codec;
	m_codecCtx = codecCtx;
	m_formatCtx = formatCtx;
	m_videoStream = videoStream;
	m_frame = av_frame_alloc();
	m_frameDeinterlaced = av_frame_alloc();

	// allocate buffer if deinterlacing is required
	avpicture_fill((AVPicture*)m_frameDeinterlaced,
		(uint8_t*)MEM_callocN(avpicture_get_size(
		m_codecCtx->pix_fmt,
		m_codecCtx->width, m_codecCtx->height),
		"ffmpeg deinterlace"),
		m_codecCtx->pix_fmt, m_codecCtx->width, m_codecCtx->height);

	// check if the pixel format supports Alpha
	if (m_codecCtx->pix_fmt == AV_PIX_FMT_RGB32 ||
		m_codecCtx->pix_fmt == AV_PIX_FMT_BGR32 ||
		m_codecCtx->pix_fmt == AV_PIX_FMT_RGB32_1 ||
		m_codecCtx->pix_fmt == AV_PIX_FMT_BGR32_1)
	{
		// allocate buffer to store final decoded frame
		m_format = RGBA32;
		// allocate sws context
		m_imgConvertCtx = sws_getContext(
			m_codecCtx->width,
			m_codecCtx->height,
			m_codecCtx->pix_fmt,
			m_codecCtx->width,
			m_codecCtx->height,
			AV_PIX_FMT_RGBA,
			SWS_FAST_BILINEAR,
			NULL, NULL, NULL);
	} else
	{
		// allocate buffer to store final decoded frame
		m_format = RGB24;
		// allocate sws context
		m_imgConvertCtx = sws_getContext(
			m_codecCtx->width,
			m_codecCtx->height,
			m_codecCtx->pix_fmt,
			m_codecCtx->width,
			m_codecCtx->height,
			AV_PIX_FMT_RGB24,
			SWS_FAST_BILINEAR,
			NULL, NULL, NULL);
	}
	m_frameRGB = allocFrameRGB();

	if (!m_imgConvertCtx) {
		avcodec_close(m_codecCtx);
		m_codecCtx = NULL;
		avformat_close_input(&m_formatCtx);
		m_formatCtx = NULL;
		av_free(m_frame);
		m_frame = NULL;
		MEM_freeN(m_frameDeinterlaced->data[0]);
		av_free(m_frameDeinterlaced);
		m_frameDeinterlaced = NULL;
		MEM_freeN(m_frameRGB->data[0]);
		av_free(m_frameRGB);
		m_frameRGB = NULL;
		return -1;
	}
	return 0;
}
Esempio n. 2
0
static int startffmpeg(struct anim *anim)
{
    int i, videoStream;

    AVCodec *pCodec;
    AVFormatContext *pFormatCtx = NULL;
    AVCodecContext *pCodecCtx;
    AVRational frame_rate;
    int frs_num;
    double frs_den;
    int streamcount;

#ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
    /* The following for color space determination */
    int srcRange, dstRange, brightness, contrast, saturation;
    int *table;
    const int *inv_table;
#endif

    if (anim == NULL) return(-1);

    streamcount = anim->streamindex;

    if (avformat_open_input(&pFormatCtx, anim->name, NULL, NULL) != 0) {
        return -1;
    }

    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        avformat_close_input(&pFormatCtx);
        return -1;
    }

    av_dump_format(pFormatCtx, 0, anim->name, 0);


    /* Find the video stream */
    videoStream = -1;

    for (i = 0; i < pFormatCtx->nb_streams; i++)
        if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            if (streamcount > 0) {
                streamcount--;
                continue;
            }
            videoStream = i;
            break;
        }

    if (videoStream == -1) {
        avformat_close_input(&pFormatCtx);
        return -1;
    }

    pCodecCtx = pFormatCtx->streams[videoStream]->codec;

    /* Find the decoder for the video stream */
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if (pCodec == NULL) {
        avformat_close_input(&pFormatCtx);
        return -1;
    }

    pCodecCtx->workaround_bugs = 1;

    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        avformat_close_input(&pFormatCtx);
        return -1;
    }

    frame_rate = av_get_r_frame_rate_compat(pFormatCtx->streams[videoStream]);
    if (pFormatCtx->streams[videoStream]->nb_frames != 0) {
        anim->duration = pFormatCtx->streams[videoStream]->nb_frames;
    }
    else {
        anim->duration = ceil(pFormatCtx->duration *
                              av_q2d(frame_rate) /
                              AV_TIME_BASE);
    }

    frs_num = frame_rate.num;
    frs_den = frame_rate.den;

    frs_den *= AV_TIME_BASE;

    while (frs_num % 10 == 0 && frs_den >= 2.0 && frs_num > 10) {
        frs_num /= 10;
        frs_den /= 10;
    }

    anim->frs_sec = frs_num;
    anim->frs_sec_base = frs_den;

    anim->params = 0;

    anim->x = pCodecCtx->width;
    anim->y = av_get_cropped_height_from_codec(pCodecCtx);

    anim->pFormatCtx = pFormatCtx;
    anim->pCodecCtx = pCodecCtx;
    anim->pCodec = pCodec;
    anim->videoStream = videoStream;

    anim->interlacing = 0;
    anim->orientation = 0;
    anim->framesize = anim->x * anim->y * 4;

    anim->curposition = -1;
    anim->last_frame = 0;
    anim->last_pts = -1;
    anim->next_pts = -1;
    anim->next_packet.stream_index = -1;

    anim->pFrame = av_frame_alloc();
    anim->pFrameComplete = false;
    anim->pFrameDeinterlaced = av_frame_alloc();
    anim->pFrameRGB = av_frame_alloc();

    if (need_aligned_ffmpeg_buffer(anim)) {
        anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
        anim->pFrameRGB->width  = anim->x;
        anim->pFrameRGB->height = anim->y;

        if (av_frame_get_buffer(anim->pFrameRGB, 32) < 0) {
            fprintf(stderr, "Could not allocate frame data.\n");
            avcodec_close(anim->pCodecCtx);
            avformat_close_input(&anim->pFormatCtx);
            av_frame_free(&anim->pFrameRGB);
            av_frame_free(&anim->pFrameDeinterlaced);
            av_frame_free(&anim->pFrame);
            anim->pCodecCtx = NULL;
            return -1;
        }
    }

    if (avpicture_get_size(AV_PIX_FMT_RGBA, anim->x, anim->y) !=
            anim->x * anim->y * 4)
    {
        fprintf(stderr,
                "ffmpeg has changed alloc scheme ... ARGHHH!\n");
        avcodec_close(anim->pCodecCtx);
        avformat_close_input(&anim->pFormatCtx);
        av_frame_free(&anim->pFrameRGB);
        av_frame_free(&anim->pFrameDeinterlaced);
        av_frame_free(&anim->pFrame);
        anim->pCodecCtx = NULL;
        return -1;
    }

    if (anim->ib_flags & IB_animdeinterlace) {
        avpicture_fill((AVPicture *) anim->pFrameDeinterlaced,
                       MEM_callocN(avpicture_get_size(
                                       anim->pCodecCtx->pix_fmt,
                                       anim->pCodecCtx->width,
                                       anim->pCodecCtx->height),
                                   "ffmpeg deinterlace"),
                       anim->pCodecCtx->pix_fmt,
                       anim->pCodecCtx->width,
                       anim->pCodecCtx->height);
    }

    if (pCodecCtx->has_b_frames) {
        anim->preseek = 25; /* FIXME: detect gopsize ... */
    }
    else {
        anim->preseek = 0;
    }

    anim->img_convert_ctx = sws_getContext(
                                anim->x,
                                anim->y,
                                anim->pCodecCtx->pix_fmt,
                                anim->x,
                                anim->y,
                                AV_PIX_FMT_RGBA,
                                SWS_FAST_BILINEAR | SWS_PRINT_INFO | SWS_FULL_CHR_H_INT,
                                NULL, NULL, NULL);

    if (!anim->img_convert_ctx) {
        fprintf(stderr,
                "Can't transform color space??? Bailing out...\n");
        avcodec_close(anim->pCodecCtx);
        avformat_close_input(&anim->pFormatCtx);
        av_frame_free(&anim->pFrameRGB);
        av_frame_free(&anim->pFrameDeinterlaced);
        av_frame_free(&anim->pFrame);
        anim->pCodecCtx = NULL;
        return -1;
    }

#ifdef FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
    /* Try do detect if input has 0-255 YCbCR range (JFIF Jpeg MotionJpeg) */
    if (!sws_getColorspaceDetails(anim->img_convert_ctx, (int **)&inv_table, &srcRange,
                                  &table, &dstRange, &brightness, &contrast, &saturation))
    {
        srcRange = srcRange || anim->pCodecCtx->color_range == AVCOL_RANGE_JPEG;
        inv_table = sws_getCoefficients(anim->pCodecCtx->colorspace);

        if (sws_setColorspaceDetails(anim->img_convert_ctx, (int *)inv_table, srcRange,
                                     table, dstRange, brightness, contrast, saturation))
        {
            fprintf(stderr, "Warning: Could not set libswscale colorspace details.\n");
        }
    }
    else {
        fprintf(stderr, "Warning: Could not set libswscale colorspace details.\n");
    }
#endif

    return (0);
}
Esempio n. 3
0
static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position,
                               IMB_Timecode_Type tc)
{
    int64_t pts_to_search = 0;
    double frame_rate;
    double pts_time_base;
    long long st_time;
    struct anim_index *tc_index = 0;
    AVStream *v_st;
    int new_frame_index = 0; /* To quiet gcc barking... */
    int old_frame_index = 0; /* To quiet gcc barking... */

    if (anim == NULL) return (0);

    av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: pos=%d\n", position);

    if (tc != IMB_TC_NONE) {
        tc_index = IMB_anim_open_index(anim, tc);
    }

    v_st = anim->pFormatCtx->streams[anim->videoStream];

    frame_rate = av_q2d(av_get_r_frame_rate_compat(v_st));

    st_time = anim->pFormatCtx->start_time;
    pts_time_base = av_q2d(v_st->time_base);

    if (tc_index) {
        new_frame_index = IMB_indexer_get_frame_index(
                              tc_index, position);
        old_frame_index = IMB_indexer_get_frame_index(
                              tc_index, anim->curposition);
        pts_to_search = IMB_indexer_get_pts(
                            tc_index, new_frame_index);
    }
    else {
        pts_to_search = (long long)
                        floor(((double) position) /
                              pts_time_base / frame_rate + 0.5);

        if (st_time != AV_NOPTS_VALUE) {
            pts_to_search += st_time / pts_time_base / AV_TIME_BASE;
        }
    }

    av_log(anim->pFormatCtx, AV_LOG_DEBUG,
           "FETCH: looking for PTS=%lld "
           "(pts_timebase=%g, frame_rate=%g, st_time=%lld)\n",
           (long long int)pts_to_search, pts_time_base, frame_rate, st_time);

    if (anim->last_frame &&
            anim->last_pts <= pts_to_search && anim->next_pts > pts_to_search)
    {
        av_log(anim->pFormatCtx, AV_LOG_DEBUG,
               "FETCH: frame repeat: last: %lld next: %lld\n",
               (long long int)anim->last_pts,
               (long long int)anim->next_pts);
        IMB_refImBuf(anim->last_frame);
        anim->curposition = position;
        return anim->last_frame;
    }

    if (position > anim->curposition + 1 &&
            anim->preseek &&
            !tc_index &&
            position - (anim->curposition + 1) < anim->preseek)
    {
        av_log(anim->pFormatCtx, AV_LOG_DEBUG,
               "FETCH: within preseek interval (no index)\n");

        ffmpeg_decode_video_frame_scan(anim, pts_to_search);
    }
    else if (tc_index &&
             IMB_indexer_can_scan(tc_index, old_frame_index,
                                  new_frame_index))
    {
        av_log(anim->pFormatCtx, AV_LOG_DEBUG,
               "FETCH: within preseek interval "
               "(index tells us)\n");

        ffmpeg_decode_video_frame_scan(anim, pts_to_search);
    }
    else if (position != anim->curposition + 1) {
        long long pos;
        int ret;

        if (tc_index) {
            unsigned long long dts;

            pos = IMB_indexer_get_seek_pos(
                      tc_index, new_frame_index);
            dts = IMB_indexer_get_seek_pos_dts(
                      tc_index, new_frame_index);

            av_log(anim->pFormatCtx, AV_LOG_DEBUG,
                   "TC INDEX seek pos = %lld\n", pos);
            av_log(anim->pFormatCtx, AV_LOG_DEBUG,
                   "TC INDEX seek dts = %llu\n", dts);

            if (ffmpeg_seek_by_byte(anim->pFormatCtx)) {
                av_log(anim->pFormatCtx, AV_LOG_DEBUG,
                       "... using BYTE pos\n");

                ret = av_seek_frame(anim->pFormatCtx,
                                    -1,
                                    pos, AVSEEK_FLAG_BYTE);
                av_update_cur_dts(anim->pFormatCtx, v_st, dts);
            }
            else {
                av_log(anim->pFormatCtx, AV_LOG_DEBUG,
                       "... using DTS pos\n");
                ret = av_seek_frame(anim->pFormatCtx,
                                    anim->videoStream,
                                    dts, AVSEEK_FLAG_BACKWARD);
            }
        }
        else {
            pos = (long long) (position - anim->preseek) *
                  AV_TIME_BASE / frame_rate;

            av_log(anim->pFormatCtx, AV_LOG_DEBUG,
                   "NO INDEX seek pos = %lld, st_time = %lld\n",
                   pos, (st_time != AV_NOPTS_VALUE) ? st_time : 0);

            if (pos < 0) {
                pos = 0;
            }

            if (st_time != AV_NOPTS_VALUE) {
                pos += st_time;
            }

            av_log(anim->pFormatCtx, AV_LOG_DEBUG,
                   "NO INDEX final seek pos = %lld\n", pos);

            ret = av_seek_frame(anim->pFormatCtx, -1,
                                pos, AVSEEK_FLAG_BACKWARD);
        }

        if (ret < 0) {
            av_log(anim->pFormatCtx, AV_LOG_ERROR,
                   "FETCH: "
                   "error while seeking to DTS = %lld "
                   "(frameno = %d, PTS = %lld): errcode = %d\n",
                   pos, position, (long long int)pts_to_search, ret);
        }

        avcodec_flush_buffers(anim->pCodecCtx);

        anim->next_pts = -1;

        if (anim->next_packet.stream_index == anim->videoStream) {
            av_free_packet(&anim->next_packet);
            anim->next_packet.stream_index = -1;
        }

        /* memset(anim->pFrame, ...) ?? */

        if (ret >= 0) {
            ffmpeg_decode_video_frame_scan(anim, pts_to_search);
        }
    }
    else if (position == 0 && anim->curposition == -1) {
        /* first frame without seeking special case... */
        ffmpeg_decode_video_frame(anim);
    }
    else {
        av_log(anim->pFormatCtx, AV_LOG_DEBUG,
               "FETCH: no seek necessary, just continue...\n");
    }

    IMB_freeImBuf(anim->last_frame);
    anim->last_frame = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);
    anim->last_frame->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace);

    ffmpeg_postprocess(anim);

    anim->last_pts = anim->next_pts;

    ffmpeg_decode_video_frame(anim);

    anim->curposition = position;

    IMB_refImBuf(anim->last_frame);

    return anim->last_frame;
}
Esempio n. 4
0
static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
                                short *stop, short *do_update, float *progress)
{
	AVFrame *in_frame = 0;
	AVPacket next_packet;
	uint64_t stream_size;

	memset(&next_packet, 0, sizeof(AVPacket));

	in_frame = av_frame_alloc();

	stream_size = avio_size(context->iFormatCtx->pb);

	context->frame_rate = av_q2d(av_get_r_frame_rate_compat(context->iFormatCtx, context->iStream));
	context->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) {
				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(
			        context->iCodecCtx, in_frame, &frame_finished,
			        &next_packet);
		}

		if (frame_finished) {
			index_rebuild_ffmpeg_proc_decoded_frame(
				context, &next_packet, in_frame);
		}
		av_free_packet(&next_packet);
	}

	/* process pictures still stuck in decoder engine after EOF
	 * according to ffmpeg docs using 0-size packets.
	 *
	 * At least, if we haven't already stopped... */

	/* this creates the 0-size packet and prevents a memory leak. */
	av_free_packet(&next_packet);

	if (!*stop) {
		int frame_finished;

		do {
			frame_finished = 0;

			avcodec_decode_video2(
				context->iCodecCtx, in_frame, &frame_finished,
				&next_packet);

			if (frame_finished) {
				index_rebuild_ffmpeg_proc_decoded_frame(
					context, &next_packet, in_frame);
			}
		} while (frame_finished);
	}

	av_free(in_frame);

	return 1;
}