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

📄 ffmpeg_audio.cpp

📁 彩信浏览器
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// This file is part of Ambulant Player, www.ambulantplayer.org.//// Copyright (C) 2003-2007 Stichting CWI, // Kruislaan 413, 1098 SJ Amsterdam, The Netherlands.//// Ambulant Player is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published by// the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// Ambulant Player is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with Ambulant Player; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA //#include <math.h>//#include <map>#include "ambulant/config/config.h"#include "ambulant/net/ffmpeg_common.h"#include "ambulant/net/ffmpeg_audio.h" #include "ambulant/net/ffmpeg_factory.h" #include "ambulant/net/demux_datasource.h" // WARNING: turning on AM_DBG globally for the ffmpeg code seems to trigger// a condition that makes the whole player hang or collapse. So you probably// shouldn't do it:-)//#define AM_DBG#ifndef AM_DBG#define AM_DBG if(0)#endif using namespace ambulant;using namespace net;typedef lib::no_arg_callback<ffmpeg_decoder_datasource> readdone_callback;typedef lib::no_arg_callback<ffmpeg_resample_datasource> resample_callback;#define INBUF_SIZE 4096// Factory functionsaudio_datasource_factory *ambulant::net::get_ffmpeg_audio_datasource_factory(){#if 0	static audio_datasource_factory *s_factory;		if (!s_factory) s_factory = new ffmpeg_audio_datasource_factory();	return s_factory;#else	return new ffmpeg_audio_datasource_factory();#endif}audio_decoder_finder *ambulant::net::get_ffmpeg_audio_decoder_finder(){#if 0	static audio_parser_finder *s_factory;		if (!s_factory) s_factory = new ffmpeg_audio_decoder_finder();	return s_factory;#else	return new ffmpeg_audio_decoder_finder();#endif}audio_filter_finder *ambulant::net::get_ffmpeg_audio_filter_finder(){#if 0	static audio_filter_finder *s_factory;		if (!s_factory) s_factory = new ffmpeg_audio_filter_finder();	return s_factory;#else	return new ffmpeg_audio_filter_finder();#endif}audio_datasource* ffmpeg_audio_datasource_factory::new_audio_datasource(const net::url& url, const audio_format_choices& fmts, timestamp_t clip_begin, timestamp_t clip_end){		AM_DBG lib::logger::get_logger()->debug("ffmpeg_audio_datasource_factory::new_audio_datasource(%s)", repr(url).c_str());	// First we check that the file format is supported by the file reader.	// If it is we create a file reader (demux head end).	AVFormatContext *context = ffmpeg_demux::supported(url);	if (!context) {		lib::logger::get_logger()->trace("ffmpeg: no support for %s", repr(url).c_str());		return NULL;	}	ffmpeg_demux *thread = new ffmpeg_demux(context, clip_begin, clip_end);	// Now, we can check that there is actually audio in the file.	if (thread->audio_stream_nr() < 0) {		thread->cancel();		lib::logger::get_logger()->trace("ffmpeg: No audio stream in %s", repr(url).c_str());		return NULL;	}		// Next, if there is audio we check that it is either in a format our caller wants,	// or we can decode this type of audio stream.	//	// XXX This code is incomplete. There could be more audio streams in the file,	// and we could have trouble decoding the first one but not others.... Oh well...	audio_format fmt = thread->get_audio_format();	if (!fmts.contains(fmt) && !ffmpeg_decoder_datasource::supported(fmt)) {		thread->cancel();		lib::logger::get_logger()->trace("ffmpeg: Unsupported audio stream in %s", repr(url).c_str());		return NULL;	}	// All seems well. Create the demux reader, the decoder and optionally the resampler.	pkt_audio_datasource *pds = demux_audio_datasource::new_demux_audio_datasource(url, thread);	if (pds == NULL) {		AM_DBG lib::logger::get_logger()->debug("fdemux_audio_datasource_factory::new_audio_datasource: could not allocate ffmpeg_video_datasource");		thread->cancel();		return NULL;	}	pds->read_ahead(clip_begin);		AM_DBG lib::logger::get_logger()->debug("ffmpeg_audio_datasource_factory::new_audio_datasource: parser ds = 0x%x", (void*)pds);	// XXXX This code should become generalized in datasource_factory	// XXXX It is also unclear whether this code will work for, say, wav or aiff streams.	audio_datasource *dds = new ffmpeg_decoder_datasource(pds);	AM_DBG lib::logger::get_logger()->debug("ffmpeg_audio_datasource_factory::new_audio_datasource: decoder ds = 0x%x", (void*)dds);	if (dds == NULL) {		int rem = pds->release();		assert(rem == 0);		return NULL;	}	if (fmts.contains(dds->get_audio_format())) {		AM_DBG lib::logger::get_logger()->debug("ffmpeg_audio_datasource_factory::new_audio_datasource: matches!");		return dds;	}	audio_datasource *rds = new ffmpeg_resample_datasource(dds, fmts);	AM_DBG lib::logger::get_logger()->debug("ffmpeg_audio_datasource_factory::new_audio_datasource: resample ds = 0x%x", (void*)rds);	if (rds == NULL)  {		int rem = dds->release();		assert(rem == 0);		return NULL;	}	if (fmts.contains(rds->get_audio_format())) {		AM_DBG lib::logger::get_logger()->debug("ffmpeg_audio_datasource_factory::new_audio_datasource: matches!");		return rds;	}	lib::logger::get_logger()->error(gettext("%s: unable to create audio resampler"));	int rem = rds->release();	assert(rem == 0);	return NULL;	}audio_datasource* ffmpeg_audio_decoder_finder::new_audio_decoder(pkt_audio_datasource *src, const audio_format_choices& fmts){	if (src == NULL) return NULL;	audio_datasource *ds = NULL;	if (!ffmpeg_decoder_datasource::supported(src->get_audio_format())) {		AM_DBG lib::logger::get_logger()->debug("ffmpeg_audio_parser_finder::new_audio_parser: no support for format");		return NULL;	}	ds = new ffmpeg_decoder_datasource(src);	if (ds == NULL) {		return NULL;	}	return ds;	}audio_datasource*ffmpeg_audio_filter_finder::new_audio_filter(audio_datasource *src, const audio_format_choices& fmts){	audio_format& fmt = src->get_audio_format();	// First check that we understand the source format	if (fmt.bits != 16) {		lib::logger::get_logger()->warn(gettext("No support for %d-bit audio, only 16"), fmt.bits);		return NULL;	}	if (fmts.contains(fmt)) {		AM_DBG lib::logger::get_logger()->debug("ffmpeg_audio_filter_finder::new_audio_datasource: matches!");		return src;	}	// XXXX Check that there is at least one destination format we understand too	return new ffmpeg_resample_datasource(src, fmts);}// **************************** ffpmeg_decoder_datasource *****************************boolffmpeg_decoder_datasource::supported(const audio_format& fmt){	if (fmt.name == "ffmpeg"){		AVCodecContext *enc = (AVCodecContext *)fmt.parameters;		if (enc->codec_type != CODEC_TYPE_AUDIO) return false;		if (avcodec_find_decoder(enc->codec_id) == NULL) return false;		return true;	}	if (fmt.name == "live"){		//AVCodecContext *enc = (AVCodecContext *)fmt.parameters;		const char* codec_name = (char*) fmt.parameters;			ffmpeg_codec_id* codecid = ffmpeg_codec_id::instance();		AVCodec *codec = avcodec_find_decoder(codecid->get_codec_id(codec_name));				if( !codec) {			return false;		}			return true;	}	return false;}// Hack, hack. Get extension of a URL.static const char *getext(const net::url &url){	const char *curl = url.get_path().c_str();	const char *dotpos = rindex(curl, '.');	if (dotpos) return dotpos+1;	return NULL;}boolffmpeg_decoder_datasource::supported(const net::url& url){	const char *ext = getext(url);	if (ext == NULL || avcodec_find_decoder_by_name(ext) == NULL) return false;	return true;}ffmpeg_decoder_datasource::ffmpeg_decoder_datasource(const net::url& url, pkt_audio_datasource *const src):	m_con(NULL),	m_fmt(audio_format(0,0,0)),	m_event_processor(NULL),	m_src(src),	m_elapsed(m_src->get_start_time()),	m_is_audio_ds(false),	m_client_callback(NULL){	AM_DBG lib::logger::get_logger()->debug("ffmpeg_decoder_datasource::ffmpeg_decoder_datasource() -> 0x%x m_buffer=0x%x", (void*)this, (void*)&m_buffer);	ffmpeg_init();	const char *ext = getext(url);	AM_DBG lib::logger::get_logger()->debug("ffmpeg_decoder_datasource: Selecting \"%s\" decoder", ext);	if (!_select_decoder(ext))		lib::logger::get_logger()->error(gettext("%s: audio decoder \"%s\" not supported"), url.get_url().c_str(), ext);}ffmpeg_decoder_datasource::ffmpeg_decoder_datasource(pkt_audio_datasource *const src):	m_con(NULL),	m_fmt(src->get_audio_format()),	m_event_processor(NULL),	m_src(src),	m_elapsed(m_src->get_start_time()),	m_is_audio_ds(true),	m_client_callback(NULL){	AM_DBG lib::logger::get_logger()->debug("ffmpeg_decoder_datasource::ffmpeg_decoder_datasource() -> 0x%x m_buffer=0x%x", (void*)this, (void*)&m_buffer);	ffmpeg_init();	audio_format fmt = src->get_audio_format();	AM_DBG lib::logger::get_logger()->debug("ffmpeg_decoder_datasource: Looking for %s(0x%x) decoder", fmt.name.c_str(), fmt.parameters);	if (!_select_decoder(fmt)) {		lib::logger::get_logger()->error(gettext("ffmpeg_decoder_datasource: could not select %s(0x%x) decoder"), fmt.name.c_str(), fmt.parameters);	}}ffmpeg_decoder_datasource::~ffmpeg_decoder_datasource(){	stop();}voidffmpeg_decoder_datasource::stop(){	m_lock.enter();	AM_DBG lib::logger::get_logger()->debug("ffmpeg_decoder_datasource::stop(0x%x)", (void*)this);	if (m_con) {		avcodec_close(m_con);		av_free(m_con);	}	m_con = NULL;	if (m_src) {		m_src->stop();		int rem = m_src->release();		if (rem) lib::logger::get_logger()->debug("ffmpeg_decoder_datasource::stop(0x%x): m_src refcount=%d", (void*)this, rem); 	}	m_src = NULL;	if (m_client_callback) delete m_client_callback;	m_client_callback = NULL;	m_lock.leave();}			  void ffmpeg_decoder_datasource::start(ambulant::lib::event_processor *evp, ambulant::lib::event *callbackk){	m_lock.enter();	bool restart_input = false;	if (m_client_callback != NULL) {		delete m_client_callback;		m_client_callback = NULL;		AM_DBG lib::logger::get_logger()->debug("ffmpeg_decoder_datasource::start(): m_client_callback already set!");	}	if (m_buffer.buffer_not_empty() || _end_of_file() ) {		// We have data (or EOF) available. Don't bother starting up our source again, in stead		// immedeately signal our client again		if (callbackk) {			assert(evp);			AM_DBG lib::logger::get_logger()->debug("ffmpeg_decoder_datasource::start: trigger client callback");			evp->add_event(callbackk, 0, ambulant::lib::ep_med);		} else {			lib::logger::get_logger()->debug("ffmpeg_decoder_datasource::start(): no client callback!");			lib::logger::get_logger()->warn(gettext("Programmer error encountered during audio playback"));		}	} else {		// We have no data available. Start our source, and in our data available callback we		// will signal the client.		restart_input = true;		m_client_callback = callbackk;		m_event_processor = evp;	}		// Also restart our source if we still have room and there is	// data to read.	if ( !_end_of_file() && !m_buffer.buffer_full() ) restart_input = true;		if (restart_input) {		lib::event *e = new readdone_callback(this, &ffmpeg_decoder_datasource::data_avail);

⌨️ 快捷键说明

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