📄 mediapacketbuffer.cpp
字号:
/************************************************************************ Copyright (C) 2000-2005 Trolltech AS and its licensors.** All rights reserved.**** This file is part of the Qtopia Environment.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.trolltech.com/gpl/ for GPL licensing information.** See below for additional copyright and license information**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "mediapacketbuffer.h"#define PACKET_BUFFER_SIZE 500MediaPacketBuffer::MediaPacketBuffer() : avFormatMutex(), bufferMutex(){ setJoin(false); FFAutoLockUnlockMutex streamLock(avFormatMutex); FFAutoLockUnlockMutex bufferLock(bufferMutex); avFormatContext = 0; openFlag.assign(0); pthread_create(&threadId, 0, (void *(*)(void *))MediaPacketBuffer::startThreadLoop, this);}MediaPacketBuffer::~MediaPacketBuffer(){ // qDebug("MediaPacketBuffer::~MediaPacketBuffer()"); join(); // qDebug("MediaPacketBuffer::~MediaPacketBuffer() finished");}void *MediaPacketBuffer::startThreadLoop(void *arg){ MediaPacketBuffer *context = (MediaPacketBuffer *)arg; qDebug("media packet buffer thread started"); while ( !context->isJoin() ) { // qDebug("media packet buffer waiting for file open"); context->bufferMutex.wait(); // EOF or stopped, wait until we are signaled again (another file opened or seeked) qDebug("media packet buffer thread resumed"); while ( context->isOpen() ) { // qDebug("buffering packets"); context->startBufferingPackets(); context->bufferMutex.timedWait(500000); // Buffer has been filled, wait 500ms for buffer to get used a bit // qDebug("media packet buffer waiting for packets to be used"); } qDebug("media packet buffer thread paused"); } sched_yield(); // So we can wait for the pthread_join() qDebug("media packet buffer thread ended"); return 0;}bool MediaPacketBuffer::open(const QString &fileName){ FFAutoLockUnlockMutex streamLock(avFormatMutex); FFAutoLockUnlockMutex bufferLock(bufferMutex); // open the input file with generic libav function if ( av_open_input_file(&avFormatContext, QFile::encodeName(fileName).data(), NULL, 0, 0) < 0 ) { // strInfo = qApp->translate( "LibFFMpegPlugin", "Error: Could not open stream: " ) + fileName; qDebug(" Error opening %s", fileName.latin1() ); avFormatContext = 0; openFlag.assign(0); return false; } qDebug(" Opened %s", fileName.latin1() ); // Decode first frames to get stream parameters (for some stream types like mpeg) if ( !avFormatContext || av_find_stream_info(avFormatContext) < 0 ) { qDebug(" Error getting parameters for %s", fileName.latin1() ); if ( avFormatContext ) av_close_input_file( avFormatContext ); avFormatContext = 0; openFlag.assign(0); return false; } audioCodecContext = 0; videoCodecContext = 0; // update the current parameters so that they match the one of the input stream for ( int i = 0; i < avFormatContext->nb_streams; i++ ) { AVCodecContext *enc = &avFormatContext->streams[i]->codec; AVCodec *c = avcodec_find_decoder( enc->codec_id ); if ( !c ) { qDebug(" Unsupported codec for stream[%i], with codec id %i", i, enc->codec_id); } else if ( avcodec_open( enc, c ) < 0 ) { qDebug(" Error opening codec for stream[%i], with codec id %i, codec: %s", i, enc->codec_id, c->name); } else { switch (enc->codec_type) { case CODEC_TYPE_AUDIO: qDebug(" Found audio stream[%i], with codec id %2i, codec: %s", i, enc->codec_id, c->name); audioStream.assign(i); audioCodecContext = enc; break; case CODEC_TYPE_VIDEO: qDebug(" Found video stream[%i], with codec id %2i, codec: %s", i, enc->codec_id, c->name); videoStream.assign(i); videoCodecContext = enc; break; default: qDebug(" Found unknown stream type, stream[%i], with codec id %2i, codec: %s", i, enc->codec_id, c->name); break; } } } openFlag.assign(1); return true;}void MediaPacketBuffer::start(){ bufferMutex.signal(); bufferMutex.signal();}MediaPacket *MediaPacketBuffer::getPacket(){ FFAutoLockUnlockMutex streamLock(avFormatMutex); // read a packet from input AVPacket avPkt; int readFailures = 0; // Wait for file to be opened and successful read while (!avFormatContext || av_read_packet(avFormatContext, &avPkt) < 0) { if ( avFormatContext && url_feof( &avFormatContext->pb ) ) return 0; // EOF readFailures++; if ( readFailures > 20 ) { qDebug("too many read failures, assuming EOF"); return 0; // EOF, clearly we can't get any more packets out, and we aren't getting an eof, something wrong } avFormatMutex.unlock(); avFormatMutex.timedWait(100000); // wait a moment, this could be streamed data which takes time to read avFormatMutex.lock(); } MediaPacket *pkt = new MediaPacket(avPkt); pkt->fileOffset = url_ftell( &avFormatContext->pb ); // convert pts (presentation timestamp) to milliseconds if ((unsigned long long)avPkt.pts != AV_NOPTS_VALUE && avFormatContext->pts_den) pkt->msecOffset = avPkt.pts * 1000 * avFormatContext->pts_num / avFormatContext->pts_den; else pkt->msecOffset = 0; return pkt;}bool MediaPacketBuffer::startBufferingPackets(){ int bufferedPackets = waitingAudioPackets.count() + waitingVideoPackets.count(); while ( isOpen() && bufferedPackets <= PACKET_BUFFER_SIZE ) { MediaPacket *pkt = getPacket(); if ( pkt ) { if ( pkt->pkt.stream_index == (int)audioStream ) { waitingAudioPackets.append( pkt ); } else if ( pkt->pkt.stream_index == (int)videoStream ) { waitingVideoPackets.append( pkt ); } } else { FFAutoLockUnlockMutex streamLock(avFormatMutex); MediaPacket *pkt1 = new MediaPacket(); MediaPacket *pkt2 = new MediaPacket(); waitingAudioPackets.append(pkt1); waitingVideoPackets.append(pkt2); qDebug("media packet buffering stopped, EOF"); return false; } bufferedPackets = waitingAudioPackets.count() + waitingVideoPackets.count(); } // qDebug("media packet buffers refilled"); avFormatMutex.signal(); return isOpen();}MediaPacket *MediaPacketBuffer::getAnotherVideoPacket(){ MediaPacket *pkt = 0; while ( !pkt && (int)videoStream != -1 ) { pkt = waitingVideoPackets.next(); if ( pkt ) { if ( pkt->eof ) { qDebug("Video EOF"); delete pkt; return 0; } return pkt; } if ( waitingAudioPackets.count() >= PACKET_BUFFER_SIZE ) waitingAudioPackets.clear(); bufferMutex.signal(); // restart buffering thread qDebug("Video packet buffer empty"); avFormatMutex.timedWait(10000); // wait a moment for more packets to get buffered } qDebug("No video stream"); return 0;}MediaPacket *MediaPacketBuffer::getAnotherAudioPacket(){ MediaPacket *pkt = 0; while ( !pkt && (int)audioStream != -1 ) { pkt = waitingAudioPackets.next(); if ( pkt ) { if ( pkt->eof ) { qDebug("Audio EOF"); delete pkt; return 0; } return pkt; } if ( waitingVideoPackets.count() >= PACKET_BUFFER_SIZE ) // There might be video packets encoded with a video codec we waitingVideoPackets.clear(); // don't support and therefore the packets aren't getting consumed bufferMutex.signal(); // restart buffering thread qDebug("Audio packet buffer empty"); avFormatMutex.timedWait(10000); // wait a moment for more packets to get buffered } qDebug("No audio stream"); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -