📄 demux_datasource.cpp
字号:
// 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/demux_datasource.h"#include "ambulant/net/ffmpeg_audio.h"// Minimum delay#define MIN_EVENT_DELAY 1// How many video frames we would like to buffer at most#define MAX_VIDEO_FRAMES 300// How many audio packets we would like to buffer at most// This limit is indicative: if demux_audio_datasource::buffer_full()// returns true, you are advised not to throw in more data; but if// you nevertheless do, no data is lost and a DEBUG message is printed#define MAX_AUDIO_PACKETS 300// WARNING: turning on AM_DBG globally in this file 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;// **************************** demux_audio_datasource ******************************demux_audio_datasource *demux_audio_datasource::new_demux_audio_datasource( const net::url& url, abstract_demux *thread){ int stream_index; AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::new_demux_audio_datasource()"); // Find the index of the audio stream stream_index = thread->audio_stream_nr(); assert(stream_index >= 0); if (stream_index >= thread->nstreams()) { lib::logger::get_logger()->error(gettext("%s: no more audio streams"), url.get_url().c_str()); return NULL; } AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::new_demux_audio_datasource() looking for the right codec"); return new demux_audio_datasource(url, thread, stream_index);}demux_audio_datasource::demux_audio_datasource(const net::url& url, abstract_demux *thread, int stream_index): m_url(url), m_stream_index(stream_index),// m_fmt(audio_format("ffmpeg")), m_src_end_of_file(false), m_event_processor(NULL), m_thread(thread), m_client_callback(NULL){ //AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::demux_audio_datasource: rate=%d, channels=%d", context->streams[m_stream_index]->codec.sample_rate, context->streams[m_stream_index]->codec.channels); // XXX ignoring the codec for now but i'll have to look into this real soon //m_fmt.parameters = (void *)&context->streams[m_stream_index]->codec; m_thread->add_datasink(this, stream_index);}demux_audio_datasource::~demux_audio_datasource(){ AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::~demux_audio_datasource(0x%x)", (void*)this); stop();}voiddemux_audio_datasource::stop(){ m_lock.enter(); AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::stop(0x%x)", (void*)this); if (m_thread) { abstract_demux *tmpthread = m_thread; m_thread = NULL; m_lock.leave(); tmpthread->remove_datasink(m_stream_index); m_lock.enter(); } m_thread = NULL; AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::stop: thread stopped"); //if (m_con) delete m_con; //m_con = NULL; // owned by the thread if (m_client_callback) delete m_client_callback; m_client_callback = NULL; m_lock.leave();} void demux_audio_datasource::start(ambulant::lib::event_processor *evp, ambulant::lib::event *callbackk){ m_lock.enter(); assert(m_thread); m_thread->start(); if (m_client_callback != NULL) { delete m_client_callback; m_client_callback = NULL; AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::start(): m_client_callback already set!"); } if (m_queue.size() > 0) { // 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("demux_audio_datasource::start: trigger client callback"); evp->add_event(callbackk, MIN_EVENT_DELAY, ambulant::lib::ep_med); } else { lib::logger::get_logger()->debug("Internal error: demux_audio_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. m_client_callback = callbackk; m_event_processor = evp; } m_lock.leave();} void demux_audio_datasource::seek(timestamp_t time){ m_lock.enter(); assert(m_thread); m_thread->seek(time); m_lock.leave();}void demux_audio_datasource::read_ahead(timestamp_t time){ m_lock.enter(); assert(m_thread); assert(!m_thread->is_running()); m_thread->seek(time); m_thread->start(); m_lock.leave();}void demux_audio_datasource::data_avail(timestamp_t pts, const uint8_t *inbuf, int sz){ // XXX timestamp is ignored, for now m_lock.enter(); m_src_end_of_file = (sz == 0); AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource.data_avail: %d bytes available (ts = %lld)", sz, pts); void* data = malloc(sz); assert(data); memcpy(data, inbuf, sz); ts_packet_t tsp(pts,data,sz); m_queue.push(tsp); int new_queue_size = m_queue.size(); if (m_queue.size() > MAX_AUDIO_PACKETS) { AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource.data_avail: m_queue.size()(=%d) exceeds desired maximum(=%d)", m_queue.size(), MAX_AUDIO_PACKETS); } m_lock.leave();}bool demux_audio_datasource::end_of_file(){ m_lock.enter(); bool rv = _end_of_file(); m_lock.leave(); return rv;}bool demux_audio_datasource::_end_of_file(){ // private method - no need to lock return m_src_end_of_file && m_queue.empty();}bool demux_audio_datasource::buffer_full(){ m_lock.enter(); bool rv = m_queue.size() >= MAX_AUDIO_PACKETS; m_lock.leave(); return rv;} ts_packet_tdemux_audio_datasource::get_ts_packet_t(){ ts_packet_t tsp(0,NULL,0); m_lock.enter(); if (m_queue.size() > 0) { tsp = m_queue.front(); m_queue.pop(); } m_lock.leave(); return tsp;}timestamp_tdemux_audio_datasource::get_clip_end(){ m_lock.enter(); assert(m_thread); timestamp_t clip_end = m_thread->get_clip_end(); AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::get_clip_end: clip_end=%d", clip_end); m_lock.leave(); return clip_end;}timestamp_tdemux_audio_datasource::get_clip_begin(){ m_lock.enter(); assert(m_thread); timestamp_t clip_begin = m_thread->get_clip_begin(); AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::get_clip_begin: clip_begin=%d", clip_begin); m_lock.leave(); return clip_begin;}audio_format&demux_audio_datasource::get_audio_format(){ assert(m_thread); return m_thread->get_audio_format();}common::durationdemux_audio_datasource::get_dur(){ common::duration rv(false, 0.0); m_lock.enter(); assert(m_thread); if (m_thread->duration() >= 0) { rv = common::duration(true, m_thread->duration()); AM_DBG lib::logger::get_logger()->debug("demux_audio_datasource::get_dur: duration=%f", rv.second); } m_lock.leave(); return rv;}// **************************** demux_video_datasource *****************************demux_video_datasource *demux_video_datasource::new_demux_video_datasource( const net::url& url, abstract_demux *thread){ int stream_index; AM_DBG lib::logger::get_logger()->debug("demux_video_datasource::new_demux_video_datasource()"); // Find the index of the audio stream stream_index = thread->video_stream_nr(); assert(stream_index >= 0); if (stream_index >= thread->nstreams()) { lib::logger::get_logger()->error(gettext("%s: no more audio streams"), url.get_url().c_str()); return NULL; } AM_DBG lib::logger::get_logger()->debug("demux_video_datasource::new_demux_video_datasource() looking for the right codec"); return new demux_video_datasource(url, thread, stream_index);}demux_video_datasource::demux_video_datasource(const net::url& url, abstract_demux *thread, int stream_index): m_url(url), m_stream_index(stream_index),// m_fmt(audio_format(0,0,0)), m_src_end_of_file(false), m_event_processor(NULL), m_thread(thread), m_client_callback(NULL), m_audio_src(NULL), m_frame_nr(0){ assert(m_thread); m_thread->add_datasink(this, stream_index); int audio_stream_idx = m_thread->audio_stream_nr(); if (audio_stream_idx >= 0) m_audio_src = new demux_audio_datasource(m_url, m_thread, audio_stream_idx); AM_DBG lib::logger::get_logger()->debug("demux_video_datasource::demux_video_datasource(0x%x) m_audio_src=0x%x url=%s", (void*)this, m_audio_src, url.get_url().c_str()); }demux_video_datasource::~demux_video_datasource(){ stop(); AM_DBG lib::logger::get_logger()->debug("demux_video_datasource::~demux_video_datasource(0x%x)", (void*)this);}voiddemux_video_datasource::stop(){ m_lock.enter(); AM_DBG lib::logger::get_logger()->debug("demux_video_datasource::stop(0x%x): m_thread=0x%x, m_client_callback=0x%x, m_frames.size()=%d", (void*)this, m_thread, m_client_callback,m_frames.size()); if (m_thread) { abstract_demux *tmpthread = m_thread; m_thread = NULL; m_lock.leave();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -