⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ffmpeg_video.cpp

📁 彩信浏览器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	if (m_fmt.frameduration <= 0) {		// And convert the timestamp#if LIBAVFORMAT_BUILD <= 4623		timestamp_t framerate = m_con->frame_rate;		timestamp_t framebase = m_con->frame_rate_base;		timestamp_t frameduration = (framebase*1000000)/framerate;		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::_need_fmt_uptodate(): frameduration = %lld", frameduration);#else		timestamp_t frameduration = (timestamp_t) round(m_con->time_base.num *1000000.0 / (double) m_con->time_base.den) ;		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::_need_fmt_uptodate(): frameduration = %lld, %d %d", frameduration, m_con->time_base.num, m_con->time_base.den);#endif		m_fmt.frameduration = frameduration;	}}voidffmpeg_video_decoder_datasource::read_ahead(timestamp_t clip_begin){	assert(m_src);	m_src->read_ahead(clip_begin);}void ffmpeg_video_decoder_datasource::data_avail(){	m_lock.enter();	int got_pic;	AVPicture picture;	int len, dummy2;	int pic_fmt, dst_pic_fmt;	int w,h;	unsigned char* ptr;		timestamp_t ipts = 0;	uint8_t *inbuf;	int sz;	got_pic = 0;		if (!m_src) {		// Cleaning up, apparently		m_lock.leave();		return;	}		// Now that we have gotten this callback we need to restart input at some point.	m_start_input = true;		// Get the input data	inbuf = (uint8_t*) m_src->get_frame(0, &ipts, &sz);		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail: %d bytes available", sz);	if(sz == 0 && !m_src->end_of_file() ) {		lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail: no data, not eof?");		m_lock.leave();		return;	}		// No easy error conditions, so let's allocate our frame.	AVFrame *frame = avcodec_alloc_frame();	AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail called (0x%x) ", (void*) this);	while(inbuf && sz && m_con) {			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail:start decoding (0x%x) ", m_con);		assert(&m_con != NULL);		assert(inbuf);		assert(sz < 1000000); // XXXX This is soft, and probably incorrect. Remove when it fails.		ptr = inbuf;				while (sz > 0) {			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail: decoding picture(s),  %d byteas of data ", sz);			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail: m_con: 0x%x, gotpic = %d, sz = %d ", m_con, got_pic, sz);			len = avcodec_decode_video(m_con, frame, &got_pic, ptr, sz);			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail: avcodec_decode_video: used %d of %d bytes, gotpic = %d, ipts = %lld", len, sz, got_pic, ipts);#if LIBAVFORMAT_BUILD > 4609            // XXX Dirac hack, to be removed.            // Some codecs (notably Dirac) always gobble up all bytes,            // and only return len==sz if got_pic is true.            len = sz;#endif			if (len >= 0) {				assert(len <= sz);				ptr +=len;					sz  -= len;				if (got_pic) {					AM_DBG lib::logger::get_logger()->debug("pts seems to be : %lld",ipts);					AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail: decoded picture, used %d bytes, %d left", len, sz);					// Setup the AVPicture for the format we want, plus the data pointer					_need_fmt_uptodate();					w = m_fmt.width;					h = m_fmt.height;					m_size = w * h * 4;					assert(m_size);					char *framedata = (char*) malloc(m_size);					AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail:framedata=0x%x", framedata);					assert(framedata != NULL);					dst_pic_fmt = PIX_FMT_RGBA32;					dummy2 = avpicture_fill(&picture, (uint8_t*) framedata, dst_pic_fmt, w, h);					// The format we have is already in frame. Convert.					pic_fmt = m_con->pix_fmt;					img_convert(&picture, dst_pic_fmt, (AVPicture*) frame, pic_fmt, w, h);#if defined(AMBULANT_PLATFORM_MACOS) && defined(__LITTLE_ENDIAN__)					// The format is now RGBARGBA, but on the Intel mac we need BGRABGRA					char *p, c;					for (p=framedata; p<framedata+m_size; p+=4) {						c = p[0];						p[0] = p[2];						p[2] = c;					}#endif					// Try and compute the timestamp and update the video clock.					timestamp_t pts = 0;					timestamp_t frame_delay = 0;				#if LIBAVFORMAT_BUILD > 4906				    pts = ipts;					if (pts != 0) {						m_video_clock = pts;					} else {						pts = m_video_clock;					}						frame_delay = m_fmt.frameduration;						if (frame->repeat_pict)							frame_delay += (timestamp_t)(frame->repeat_pict*m_fmt.frameduration*0.5);						m_video_clock += frame_delay;#else // ffmpeg 0.4.8 					if (ipts != AV_NOPTS_VALUE) pts = ipts;					if (m_con->has_b_frames && frame->pict_type != FF_B_TYPE) {						pts = m_last_p_pts;						m_last_p_pts = ipts;						AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail:frame has B frames but this frame is no B frame  (this=0x%x) ", this);						AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail:pts set to %f, remember %f", pts, m_last_p_pts);					}					if (pts != 0) {						m_video_clock = pts;					} else {						pts = m_video_clock;						frame_delay = m_fmt.frameduration;						if (frame->repeat_pict)							frame_delay += (timestamp_t)(frame->repeat_pict*m_fmt.frameduration*0.5);						m_video_clock += frame_delay;					}#endif									AM_DBG lib::logger::get_logger()->debug("videoclock: ipts=%lld pts=%lld video_clock=%lld, frame_delay=%lld", ipts, pts, m_video_clock, frame_delay);					AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail: storing frame with pts = %lld",pts );					m_frame_count++;					bool drop_this_frame = false;					if (m_con->has_b_frames && frame->pict_type == FF_B_TYPE && pts < m_src->get_clip_begin()) {						// A non-essential frame while skipping forward.						AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder: could drop B frame %d, ts=%lld", m_frame_count, pts);						drop_this_frame = true;					}					if (pts < m_old_frame.first) {						// A frame that came after this frame has already been consumed.						// We should drop this frame.						AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder: dropping frame %d: too late", m_frame_count);						drop_this_frame = true;					}					if (!drop_this_frame) {						std::pair<timestamp_t, char*> element(pts, framedata);						m_frames.push(element);					}					m_elapsed = pts;				} else {					AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail: incomplete picture, used %d bytes, %d left", len, sz);				}			} else {				lib::logger::get_logger()->error(gettext("error decoding video frame"));			}		} // End of while loop		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource.data_avail:done decoding (0x%x) ", m_con);		m_src->frame_done(0, false);  	}	av_free(frame);	// Now tell our client, if we have data available or are at end of file.	AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::data_avail(): m_frames.size() returns %d, (eof=%d)", m_frames.size(), m_src->end_of_file());	if ( m_frames.size() > MIN_VIDEO_FRAMES || m_src->end_of_file()) {		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::data_avail(): there is some data for the renderer ! (eof=%d)", m_src->end_of_file());		if ( m_client_callback ) {			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::data_avail(): calling client callback (eof=%d)", m_src->end_of_file());			assert(m_event_processor);			m_event_processor->add_event(m_client_callback, 0, ambulant::lib::ep_high);			m_client_callback = NULL;			//m_event_processor = NULL;		} else {			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::data_avail(): No client callback!");		}  	}	// Restart input if there is buffer space and anything remains to be read. Otherwise we	// leave m_start_input true, and restarting is taken care of in start_frame().	if (!m_src->end_of_file() && !_buffer_full()) {		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::start_frame() Calling m_src->start_frame(..)");		lib::event *e = new framedone_callback(this, &ffmpeg_video_decoder_datasource::data_avail);		m_src->start_frame(m_event_processor, e, ipts);		m_start_input = false;	}	m_lock.leave();}bool ffmpeg_video_decoder_datasource::end_of_file(){	m_lock.enter();	if (_clip_end()) {		m_lock.leave();		return true;	}	bool rv = _end_of_file();	m_lock.leave();	return rv;}bool ffmpeg_video_decoder_datasource::_end_of_file(){	// private method - no need to lock	if (m_frames.size() > 0)  {			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::_end_of_file() returning false (still %d frames in local buffer)", m_frames.size());			return false;	}	return m_src == NULL || m_src->end_of_file();}bool ffmpeg_video_decoder_datasource::_clip_end(){		return false;}bool ffmpeg_video_decoder_datasource::buffer_full(){	m_lock.enter();	bool rv = _buffer_full();	m_lock.leave();	return rv;}	bool ffmpeg_video_decoder_datasource::_buffer_full(){	// private method - no need to lock	AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::_buffer_full() (this=0x%x, count=%d)", (void*) this, m_frames.size());	bool rv = (m_frames.size() > MAX_VIDEO_FRAMES);	return rv;}	char* ffmpeg_video_decoder_datasource::get_frame(timestamp_t now, timestamp_t *timestamp_p, int *size_p){	// pop frames until (just before) "now". Then return the last frame popped.	m_lock.enter();	AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::get_frame(now=%lld)\n", now);	// XXX now can be negative, due to time manipulation by the scheduler. assert(now >= 0);	AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::get_frame() %d frames available\n", m_frames.size());	assert(m_frames.size() > 0 || _end_of_file());		timestamp_t frame_duration = frameduration(); 	assert (frame_duration > 0);	AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::get_frame:  timestamp=%lld, now=%lld, frameduration = %lld",m_old_frame.first,now, frame_duration);	AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::get_frame(now=%lld): %lld (m_old_frame.first) <  %lld (now - frame_duration)",  now, m_old_frame.first, now - frame_duration );#if 1	// XXX Jack thinks it may be better not to do any framedropping here, and in stead do it only in the	// renderer (where we can gather statistics)	bool firstdrop = true;	while ( m_frames.size() && m_old_frame.first < now - (2*frame_duration)) { //HACK:Due to jitter, the previous condition of dropping frames older than one frameduration was too strict!		//A better method to tolerate jitter required ??? This hack may still fail for high fps videos		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::get_frame: discarding m_old_frame timestamp=%lld, now=%lld, data ptr = 0x%x", m_old_frame.first,now, m_old_frame.second);		_pop_top_frame();		if (!firstdrop) m_dropped_count++;		firstdrop = false;	}#endif	AM_DBG if (m_frames.size()) lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::get_frame: next timestamp=%lld, now=%lld", m_frames.top().first, now);	// The next assert assures that we have indeed removed all old frames (and, therefore, either there	// are no frames left, or the first frame has a time that is in the future). It also assures that	// the frames in m_frames are indeed in the right order.#if 0	if (!(m_frames.size() == 0 || m_frames.top().first >= now-frame_duration)) {		lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::get_frame: top frame before now!");		lib::logger::get_logger()->debug("now-frameduration = %lld-%lld = %lld", now, frame_duration, now-frame_duration);		lib::logger::get_logger()->debug("m_old_frame.first = %lld", m_old_frame.first);		lib::logger::get_logger()->debug("m_frames.top().first = %lld", m_frames.top().first);		lib::logger::get_logger()->debug("go figure...");	}#endif	assert(m_frames.size() == 0 || m_frames.top().first >= now-(2*frame_duration));		 	if (timestamp_p) *timestamp_p = m_old_frame.first;	if (size_p) *size_p = m_size;	char *rv = m_old_frame.second;	m_lock.leave();	return rv;}common::durationffmpeg_video_decoder_datasource::get_dur(){	if( m_src == 0) return common::duration(0, true);	return m_src->get_dur();}bool ffmpeg_video_decoder_datasource::_select_decoder(const char* file_ext){	// private method - no need to lock	AVCodec *codec = avcodec_find_decoder_by_name(file_ext);	if (codec == NULL) {			lib::logger::get_logger()->trace("ffmpeg_video_decoder_datasource._select_decoder: Failed to find codec for \"%s\"", file_ext);			lib::logger::get_logger()->error(gettext("No support for \"%s\" video"), file_ext);			return false;	}	m_con = avcodec_alloc_context();		if(avcodec_open(m_con,codec) < 0) {			lib::logger::get_logger()->trace("ffmpeg_video_decoder_datasource._select_decoder: Failed to open avcodec for \"%s\"", file_ext);			lib::logger::get_logger()->error(gettext("No support for \"%s\" video"), file_ext);			return false;	}	return true;}bool ffmpeg_video_decoder_datasource::_select_decoder(video_format &fmt){	// private method - no need to lock	if (fmt.name == "ffmpeg") {		AVCodecContext *enc = (AVCodecContext *)fmt.parameters;		m_con = enc;		if (enc == NULL) {				lib::logger::get_logger()->debug("Internal error: ffmpeg_video_decoder_datasource._select_decoder: Parameters missing for %s(0x%x)", fmt.name.c_str(), fmt.parameters);				lib::logger::get_logger()->warn(gettext("Programmer error encountered during video playback"));				return false;		}		if (enc->codec_type != CODEC_TYPE_VIDEO) {				lib::logger::get_logger()->debug("Internal error: ffmpeg_video_decoder_datasource._select_decoder: Non-video stream for %s(0x%x)", fmt.name.c_str(), enc->codec_type);				lib::logger::get_logger()->warn(gettext("Programmer error encountered during video playback"));				return false;		}		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource._select_decoder: enc->codec_id = 0x%x", enc->codec_id);		AVCodec *codec = avcodec_find_decoder(enc->codec_id);		if (codec == NULL) {				lib::logger::get_logger()->debug("Internal error: ffmpeg_video_decoder_datasource._select_decoder: Failed to find codec for %s(0x%x)", fmt.name.c_str(),  enc->codec_id);				lib::logger::get_logger()->warn(gettext("Programmer error encountered during video playback"));				return false;		}		//m_con = avcodec_alloc_context();				if(avcodec_open(m_con,codec) < 0) {				lib::logger::get_logger()->debug("Internal error: ffmpeg_video_decoder_datasource._select_decoder: Failed to open avcodec for %s(0x%x)", fmt.name.c_str(), enc->codec_id);				lib::logger::get_logger()->warn(gettext("Programmer error encountered during video playback"));				return false;		}		if (fmt.width == 0) fmt.width = m_con->width;		if (fmt.height == 0) fmt.width = m_con->height;		return true;	} else if (fmt.name == "live") {		const char* codec_name = (char*) fmt.parameters;			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::selectdecoder(): video codec : %s", codec_name);		ffmpeg_codec_id* codecid = ffmpeg_codec_id::instance();		AVCodec *codec = avcodec_find_decoder(codecid->get_codec_id(codec_name));		if( !codec) {			return false;		}		AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::selectdecoder(): codec found!");		m_con = avcodec_alloc_context();				if((avcodec_open(m_con,codec) < 0) ) {			//lib::logger::get_logger()->error(gettext("%s: Cannot open video codec %d(%s)"), repr(url).c_str(), m_con->codec_id, m_con->codec_name);			return false;		} else {			AM_DBG lib::logger::get_logger()->debug("ffmpeg_video_decoder_datasource::ffmpeg_decoder_datasource(): succesfully opened codec");		}				m_con->codec_type = CODEC_TYPE_VIDEO;		// We doe a fmt update here to sure that we have the correct values.		_need_fmt_uptodate();		return true;	}	// Could add support here for raw mp3, etc.	return false;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -