示例#1
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 == 0) 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(v_st->r_frame_rate);

	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 = %lld\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;
}
示例#2
0
static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
	ImBuf * ibuf;
	int frameFinished;
	AVPacket packet;
	int64_t pts_to_search = 0;
	int pos_found = 1;
	int filter_y = 0;
	int seek_by_bytes= 0;
	int preseek_count = 0;

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

	ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect);

	avpicture_fill((AVPicture*) anim->pFrameRGB, 
			   (unsigned char*) ibuf->rect, 
			   PIX_FMT_RGBA, anim->x, anim->y);

	if (position != anim->curposition + 1) { 
		if (position > anim->curposition + 1 
			&& anim->preseek 
			&& position - (anim->curposition + 1) < anim->preseek) {
			while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
				if (packet.stream_index == anim->videoStream) {
					avcodec_decode_video2(
						anim->pCodecCtx, 
						anim->pFrame, &frameFinished, 
						&packet);

					if (frameFinished) {
						anim->curposition++;
					}
				}
				av_free_packet(&packet);
				if (position == anim->curposition+1) {
					break;
				}
			}
		}
	}

/* disable seek_by_bytes for now, since bitrates are guessed wrong!
   also: MPEG2TS-seeking was fixed in later versions of ffmpeg, so problem
   is somewhat fixed by now (until we add correct timecode management code...)
*/
#if 0
	seek_by_bytes = !!(anim->pFormatCtx->iformat->flags & AVFMT_TS_DISCONT);
#else
	seek_by_bytes = FALSE;
#endif

	if (position != anim->curposition + 1) { 
		double frame_rate = 
			av_q2d(anim->pFormatCtx->streams[anim->videoStream]
				   ->r_frame_rate);
		double pts_time_base = av_q2d(anim->pFormatCtx->streams[anim->videoStream]->time_base);
		long long pos;
		long long st_time = anim->pFormatCtx->start_time;
		int ret;

		if (seek_by_bytes) {
			pos = position - anim->preseek;
			if (pos < 0) {
				pos = 0;
			}
			preseek_count = position - pos;

			pos *= anim->pFormatCtx->bit_rate / frame_rate;
			pos /= 8;
		} else {
			pos = (long long) (position - anim->preseek) 
				* AV_TIME_BASE / frame_rate;
			if (pos < 0) {
				pos = 0;
			}

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

		ret = av_seek_frame(anim->pFormatCtx, -1, 
				    pos, 
				    AVSEEK_FLAG_BACKWARD | (
					    seek_by_bytes 
					    ? AVSEEK_FLAG_ANY 
					    | AVSEEK_FLAG_BYTE : 0));
		if (ret < 0) {
			fprintf(stderr, "error while seeking: %d\n", ret);
		}

		pts_to_search = (long long) 
			(((double) position) / pts_time_base / frame_rate);
		if (st_time != AV_NOPTS_VALUE) {
			pts_to_search += st_time / pts_time_base/ AV_TIME_BASE;
		}

		pos_found = 0;
		avcodec_flush_buffers(anim->pCodecCtx);
	}

	while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
		if(packet.stream_index == anim->videoStream) {
			avcodec_decode_video2(anim->pCodecCtx, 
					      anim->pFrame, &frameFinished, 
					      &packet);

			if (seek_by_bytes && preseek_count > 0) {
				preseek_count--;
			}

			if (frameFinished && !pos_found) {
				if (seek_by_bytes) {
					if (!preseek_count) {
						pos_found = 1;
						anim->curposition = position;
					}
				} else {
					if (packet.dts >= pts_to_search) {
						pos_found = 1;
						anim->curposition = position;
					}
				}
			} 

			if(frameFinished && pos_found == 1) {
				ffmpeg_postprocess(anim, ibuf, &filter_y);
				av_free_packet(&packet);
				break;
			}
		}

		av_free_packet(&packet);
	}

	if (filter_y && ibuf) {
		IMB_filtery(ibuf);
	}

	ibuf->profile = IB_PROFILE_SRGB;
	
	return(ibuf);
}