📄 ffmpeg_audio.cpp
字号:
m_fmt.samplerate = m_con->sample_rate; } if (m_fmt.channels == 0) { m_fmt.channels = m_con->channels; }}common::durationffmpeg_decoder_datasource::get_dur(){ return m_src->get_dur();}// **************************** ffmpeg_resample_datasource *****************************ffmpeg_resample_datasource::ffmpeg_resample_datasource(audio_datasource *src, audio_format_choices fmts) : m_src(src), m_context_set(false), m_resample_context(NULL), m_event_processor(NULL), m_client_callback(NULL), m_in_fmt(src->get_audio_format()), m_out_fmt(fmts.best()){ ffmpeg_init(); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::ffmpeg_resample_datasource()->0x%x m_buffer=0x%x", (void*)this, (void*)&m_buffer);#ifdef RESAMPLE_READ_ALL m_buffer.set_max_size(0);#endif}ffmpeg_resample_datasource::~ffmpeg_resample_datasource() { stop();}voidffmpeg_resample_datasource::stop() { m_lock.enter(); int oldrefcount = get_ref_count(); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::stop(0x%x)", (void*)this); if (m_src) { m_src->stop(); int rem = m_src->release(); if (rem) lib::logger::get_logger()->debug("ffmpeg_resample_datasource::stop(0x%x): m_src refcount=%d", (void*)this, rem); m_src = NULL; } else { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::stop(0x%x): m_src already NULL", (void*)this); } m_src = NULL; if (m_resample_context) audio_resample_close(m_resample_context); m_resample_context = NULL; if (m_client_callback) delete m_client_callback; m_client_callback = NULL; AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::stop(0x%x) refcount was %d is %d", (void*)this, oldrefcount, get_ref_count()); m_lock.leave();}voidffmpeg_resample_datasource::data_avail(){ m_lock.enter(); int sz; int cursize = 0; AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(0x%x) refcount is %d", (void*)this, get_ref_count()); if (!m_src) { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(0x%x): already stopping", (void*)this); m_lock.leave(); return; } // We now have enough information to determine the resample parameters if (!m_context_set) { m_in_fmt = m_src->get_audio_format(); assert(m_in_fmt.bits == 16); assert(m_out_fmt.bits == 16); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource: initializing context: inrate, ch=%d, %d, outrate, ch=%d, %d", m_in_fmt.samplerate, m_in_fmt.channels, m_out_fmt.samplerate, m_out_fmt.channels); m_resample_context = audio_resample_init(m_out_fmt.channels, m_in_fmt.channels, m_out_fmt.samplerate,m_in_fmt.samplerate); m_context_set = true; } if(m_src) { sz = m_src->size(); } else { lib::logger::get_logger()->debug("Internal error: ffmpeg_audio_datasource::data_avail: No datasource"); lib::logger::get_logger()->warn(gettext("Programmer error encountered during audio playback")); m_lock.leave(); return; } if (m_resample_context) { // Convert all the input data we have available. We make an educated guess at the number of bytes // this will produce on output. cursize = sz; // Don't feed to much data to the resampler, it doesn't like to do lists ;-) if (cursize > INBUF_SIZE) cursize = INBUF_SIZE; AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail: cursize=%d, sz=%d, in channels=%d", cursize,sz,m_in_fmt.channels); int insamples = cursize / (m_in_fmt.channels * sizeof(short)); // integer division !!!! if (insamples * m_in_fmt.channels * sizeof(short) != (size_t)cursize) { lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail: warning: incomplete samples: %d", cursize); } timestamp_t tmp = (timestamp_t)((insamples+1) * m_out_fmt.samplerate * m_out_fmt.channels * sizeof(short) / m_in_fmt.samplerate); timestamp_t outsz = tmp; if (!cursize && !m_src->end_of_file()) { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(0x%x): no data available, not end-of-file!", (void*)this); m_lock.leave(); return; } assert( cursize || m_src->end_of_file()); //if (sz & 1) lib::logger::get_logger()->warn("ffmpeg_resample_datasource::data_avail: warning: oddsized datasize %d", sz); if (!m_buffer.buffer_full()) { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): m_src->get_read_ptr() m_src=0x%x, this=0x%x",(void*) m_src, (void*) this); short int *inbuf = (short int*) m_src->get_read_ptr(); short int *outbuf = (short int*) m_buffer.get_write_ptr(outsz); if (!outbuf) { lib::logger::get_logger()->debug("Internal error: ffmpeg_audio_datasource::data_avail: no room in output buffer"); lib::logger::get_logger()->warn(gettext("Programmer error encountered during audio playback")); m_src->readdone(0); m_buffer.pushdata(0); } if (inbuf && outbuf && insamples > 0) { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail: sz=%d, insamples=%d, outsz=%d, inbuf=0x%x, outbuf=0x%x", cursize, insamples, outsz, inbuf, outbuf); int outsamples = audio_resample(m_resample_context, outbuf, inbuf, insamples); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): putting %d bytes in %d bytes buffer space", outsamples*m_out_fmt.channels*sizeof(short), outsz); assert(outsamples*m_out_fmt.channels*sizeof(short) <= outsz); m_buffer.pushdata(outsamples*m_out_fmt.channels*sizeof(short)); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): calling m_src->readdone(%d) this=0x%x", insamples*m_in_fmt.channels*sizeof(short), (void*) this); m_src->readdone(insamples*m_in_fmt.channels*sizeof(short)); } else { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): calling m_src->readdone(0) m_src=0x%x, this=0x%x", (void*) m_src, (void*) this); m_src->readdone(0); m_buffer.pushdata(0); } } // Restart reading if we still have room to accomodate more data if (!m_src->end_of_file() && m_event_processor && !m_buffer.buffer_full()) { lib::event *e = new resample_callback(this, &ffmpeg_resample_datasource::data_avail); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): calling m_src->start(), refcount=%d", get_ref_count()); m_src->start(m_event_processor, e);#ifdef RESAMPLE_READ_ALL // workaround for sdl bug: if RESAMPLE_READ_ALL is defined we continue // reading until we have all data m_lock.leave(); return;#endif /* RESAMPLE_READ_ALL */ } else { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail: not calling start: eof=%d m_ep=0x%x buffull=%d", (int)m_src->end_of_file(), (void*)m_event_processor, (int)m_buffer.buffer_full()); } // If the client is currently interested tell them about data being available if (m_client_callback && (m_buffer.buffer_not_empty() || _end_of_file() )) { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): calling client callback (%d, %d)", m_buffer.size(), _end_of_file()); assert(m_event_processor); lib::event *clientcallback = m_client_callback; m_client_callback = NULL; m_event_processor->add_event(clientcallback, 0, ambulant::lib::ep_med); //m_event_processor = NULL; } else { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): No client callback!"); } } else { // Something went wrong during initialization, we just drop the data // on the floor. AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): No resample context, flushing data"); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::data_avail(): m_src->readdone(%d) called m_src=0x%x, this=0x%x", sz, (void*) m_src, (void*) this); m_src->readdone(sz); } m_lock.leave();}void ffmpeg_resample_datasource::readdone(int len){ m_lock.enter(); m_buffer.readdone(len); AM_DBG lib::logger::get_logger()->debug("ffmpeg_decoder_datasource::readdone: done with %d bytes", len); if (!m_src->end_of_file() && m_event_processor && !m_buffer.buffer_full()) { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::readdone: calling m_src->start() again"); lib::event *e = new resample_callback(this, &ffmpeg_resample_datasource::data_avail); m_src->start(m_event_processor, e); } m_lock.leave();}bool ffmpeg_resample_datasource::end_of_file(){ m_lock.enter(); bool rv = _end_of_file(); m_lock.leave(); return rv;}bool ffmpeg_resample_datasource::_end_of_file(){ // private method - no need to lock if (m_buffer.buffer_not_empty()) return false; if (m_src) return m_src->end_of_file(); return true;}boolffmpeg_resample_datasource::_src_end_of_file() const{ // private mathod - no need to lock if (m_src) return m_src->end_of_file(); return true;}bool ffmpeg_resample_datasource::buffer_full(){ m_lock.enter(); bool rv = m_buffer.buffer_full(); m_lock.leave(); return rv;} timestamp_tffmpeg_resample_datasource::get_clip_end(){ return m_src->get_clip_end();}timestamp_tffmpeg_resample_datasource::get_clip_begin(){ return m_src->get_clip_begin();}char* ffmpeg_resample_datasource::get_read_ptr(){ m_lock.enter(); char *rv = m_buffer.get_read_ptr(); m_lock.leave(); return rv;}int ffmpeg_resample_datasource::size() const{ const_cast <ffmpeg_resample_datasource*>(this)->m_lock.enter(); int rv = m_buffer.size(); const_cast <ffmpeg_resample_datasource*>(this)->m_lock.leave(); return rv;} void ffmpeg_resample_datasource::start(ambulant::lib::event_processor *evp, ambulant::lib::event *callbackk){ m_lock.enter(); bool restart_input = false; AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start(): start(0x%x) called", this); if (m_client_callback != NULL) { delete m_client_callback; m_client_callback = NULL; AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start(): m_client_callback already set!"); } if ( m_buffer.buffer_not_empty() && _end_of_file() ) { AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start(): (%d || %d) = %d ", _end_of_file(), m_buffer.buffer_not_empty(), _end_of_file() || m_buffer.buffer_not_empty()); // We have data (or EOF) available. Don't bother starting up our source again, in stead // immedeately signal our client again restart_input = false; AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start(): no restart EOF (or clipend reached) but no data available"); if (callbackk) { assert(evp); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start: trigger client callback"); evp->add_event(callbackk, 0, ambulant::lib::ep_med); } else { lib::logger::get_logger()->error("Internal error: ffmpeg_resample_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. AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start(): (%d && %d) = %d ", !_end_of_file(), !m_buffer.buffer_full(), !_end_of_file() && !m_buffer.buffer_full()); 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. AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start(): (%d && %d) = %d ", !_end_of_file(), !m_buffer.buffer_full(), !_end_of_file() && !m_buffer.buffer_full()); if ( !_src_end_of_file() && !m_buffer.buffer_full() ) { restart_input = true; AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start(): no EOF and buffer is not full so we need to do a restart, (%d && %d) = %d ", !_end_of_file(), !m_buffer.buffer_full(), !_end_of_file() && !m_buffer.buffer_full()); } if (restart_input) { // Restart the input stream lib::event *e = new resample_callback(this, &ffmpeg_resample_datasource::data_avail); AM_DBG lib::logger::get_logger()->debug("ffmpeg_resample_datasource::start(): calling m_src->start(0x%x, 0x%x)", m_event_processor, e); m_src->start(evp, e); } m_lock.leave();}common::durationffmpeg_resample_datasource::get_dur(){ common::duration rv(false, 0.0); m_lock.enter(); if (m_src) rv = m_src->get_dur(); m_lock.leave(); return rv;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -