📄 libffmpegplugin.cpp
字号:
/************************************************************************ Copyright (C) 2000-2002 Trolltech AS. 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.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include <qfileinfo.h>#include "libffmpegplugin.h"static const int AVSyncSlack = 200;LibFFMpegPlugin::LibFFMpegPlugin(){ scaleContextDepth = -1; scaleContextInputWidth = -1; scaleContextInputHeight = -1; scaleContextPicture1Width = -1; scaleContextPicture2Width = -1; scaleContextOutputWidth = -1; scaleContextOutputHeight = -1; scaleContextLineStride = -1; audioCodecContext = 0; videoCodecContext = 0; audioScaleContext = 0; strInfo = ""; openFlag = FALSE; streamingFlag = FALSE; needPluginInit = TRUE;}LibFFMpegPlugin::~LibFFMpegPlugin(){ close(); flushAudioPackets(); flushVideoPackets();}const char *LibFFMpegPlugin::pluginName(){ return "LibFFMpegPlugin";}const char *LibFFMpegPlugin::pluginComment(){ return "This plugin uses ffmpeg, libavcodec, libav libraries written by Fabrice Bellard and others. " "The Qtopia plugin interface adaptor is created by Trolltech.";}double LibFFMpegPlugin::pluginVersion(){ return 1.0;}bool LibFFMpegPlugin::isFileSupported( const QString& fileName ){ qDebug("checking if file is supported %s", fileName.latin1() ); QString ext2 = fileName.right(3).lower(); QString ext3 = fileName.right(4).lower(); QString ext4 = fileName.right(5).lower(); return ( ( ext3 == ".asf" ) || ( ext3 == ".avi" ) || ( ext3 == ".mov" ) || ( ext3 == ".mp2" ) || ( ext3 == ".mp3" ) || ( ext4 == ".mpeg") || ( ext3 == ".mpg" ) || //( ext3 == ".ogg" ) || ( ext2 == ".rm" ) || //( ext3 == ".vob" ) || //( ext3 == ".wav" ) || ( ext3 == ".wma" ) || ( ext3 == ".wmf" ) || ( ext3 == ".wmv" ) );}void LibFFMpegPlugin::pluginInit(){ avcodec_init(); avcodec_register_all(); av_register_all(); needPluginInit = FALSE;}void LibFFMpegPlugin::fileInit(){ if ( needPluginInit ) pluginInit(); audioCodec = 0; videoCodec = 0; audioCodecContext = 0; audioScaleContext = 0; videoCodecContext = 0; streamContext = 0; frame = 0; videoStream = -1; audioStream = -1; fileLength = 0; skipNext = 0; currentPacketTimeStamp = 0; currentVideoTimeStamp = 0; currentAudioTimeStamp = 0; haveTotalTimeCache = FALSE; totalTimeCache = TRUE; droppedFrames = 0; framesInLastPacket = 0; streamingFlag = FALSE; strInfo = ""; totalFrames = 0; openFlag = TRUE;}bool LibFFMpegPlugin::open( const QString& fileName ){ qDebug("opening file %s", fileName.latin1() ); fileInit(); if ( !fileLength ) { QFileInfo fi( fileName ); fileLength = fi.size(); } // open the input file with generic libav function if ( av_open_input_file(&streamContext, fileName.latin1(), NULL, 0, 0) < 0 ) { strInfo = qApp->translate( "LibFFMpegPlugin", "Error: Could not open file, File: " ) + fileName; qDebug( "%s", strInfo.latin1() ); return FALSE; } qDebug("opened file %s", fileName.latin1() ); // Decode first frames to get stream parameters (for some stream types like mpeg) if ( av_find_stream_info(streamContext) < 0 ) { qDebug("Error getting parameters for file %s", fileName.latin1() ); return FALSE; } qDebug("initing file %s", fileName.latin1() ); // update the current parameters so that they match the one of the input stream for ( int i = 0; i < streamContext->nb_streams; i++ ) { //printf( "searching: %i\n", i ); AVCodecContext *enc = &streamContext->streams[i]->codec; enc->codec = avcodec_find_decoder( enc->codec_id ); //printf( "decoder found: %s\n", enc->codec->name ); if ( !enc->codec ) qDebug("Unsupported codec for input stream"); else if ( avcodec_open( enc, enc->codec ) < 0 ) qDebug("Error while opening codec for input stream"); else { switch (enc->codec_type) { case CODEC_TYPE_AUDIO: qDebug("setting audio stream with id: %i", i); audioStream = i; audioCodecContext = enc; break; case CODEC_TYPE_VIDEO: qDebug("setting video stream with id: %i", i); videoStream = i; videoCodecContext = enc; break; default: qDebug("unknown stream type"); break; } } } if ( audioCodecContext ) audioScaleContext = audio_resample_init( 2, audioCodecContext->channels, 44100, audioCodecContext->sample_rate ); // Try to determine the total play time if possible if ( !lengthAvailable() || !tellAvailable() ) haveTotalTimeCache = FALSE; else { // Jump to near the end of the file url_fseek( &streamContext->pb, length() - 100000, SEEK_SET ); AVPacket pkt; pkt.pts = 0; totalTimeCache = 0; // Read packets till we get to the end to try and get the last timestamp available while ( av_read_packet(streamContext, &pkt) >= 0 ) { if ( pkt.pts > totalTimeCache ) totalTimeCache = pkt.pts / 100; pkt.pts = 0; av_free_packet(&pkt); } // Jump back to the beginning so we are ready to decode url_fseek( &streamContext->pb, 0, SEEK_SET ); haveTotalTimeCache = totalTimeCache > 1; if ( !haveTotalTimeCache ) { // Calculate the play time of constant bit rate files int totalBitRate = 0; if ( audioStream != -1 && audioCodecContext ) totalBitRate += audioCodecContext->bit_rate; if ( videoStream != -1 && videoCodecContext ) totalBitRate += videoCodecContext->bit_rate; if ( totalBitRate ) { // The 8000 multiplier is because the rate is in bits per second and // there are 8 bits to a byte and we want the time in milliseconds. totalTimeCache = ((long long)length() * 8000) / totalBitRate; haveTotalTimeCache = TRUE; } } } if ( videoCodecContext ) videoCodecContext->hurry_up = 0; if ( videoCodecContext && videoCodecContext->frame_rate ) msecPerFrame = (1000 * FRAME_RATE_BASE) / videoCodecContext->frame_rate; else msecPerFrame = 1000 / 25; qDebug("finished opening %s", fileName.latin1() ); return true;}const QString &LibFFMpegPlugin::fileInfo(){ if ( strInfo == "" ) { if ( haveTotalTimeCache ) { int seconds = totalTimeCache / 1000; strInfo += qApp->translate( "LibFFMpegPlugin", "Play Time: " ) + QString::number( seconds / 60 ) + ":" + QString::number( (seconds % 60) / 10 ) + QString::number( (seconds % 60) % 10 ) + ","; } if ( audioCodecContext ) { strInfo += qApp->translate( "LibFFMpegPlugin", "Audio Tracks: 1," ); if ( audioCodecContext->codec ) strInfo += qApp->translate( "LibFFMpegPlugin", "Audio Format: " ) + audioCodecContext->codec->name + ","; strInfo += qApp->translate( "LibFFMpegPlugin", "Audio Bit Rate: " ) + QString::number( audioCodecContext->bit_rate ) + ","; strInfo += qApp->translate( "LibFFMpegPlugin", "Audio Channels: " ) + QString::number( audioCodecContext->channels ) + ","; strInfo += qApp->translate( "LibFFMpegPlugin", "Audio Frequency: " ) + QString::number( audioCodecContext->sample_rate ) + ","; } if ( videoCodecContext ) { strInfo += qApp->translate( "LibFFMpegPlugin", "Video Tracks: 1," ); if ( videoCodecContext->codec ) strInfo += qApp->translate( "LibFFMpegPlugin", "Video Format: " ) + videoCodecContext->codec->name + ","; strInfo += qApp->translate( "LibFFMpegPlugin", "Video Bit Rate: " ) + QString::number( videoCodecContext->bit_rate ) + ","; strInfo += qApp->translate( "LibFFMpegPlugin", "Video Width: " ) + QString::number( videoCodecContext->width ) + ","; strInfo += qApp->translate( "LibFFMpegPlugin", "Video Height: " ) + QString::number( videoCodecContext->height ) + ","; } } return strInfo;}static uchar bufferedSamples[AVCODEC_MAX_AUDIO_FRAME_SIZE * 16];static int bufferedSamplesCount = 0;bool LibFFMpegPlugin::close(){ if ( openFlag ) { flushAudioPackets(); flushVideoPackets(); AutoLockUnlockMutex lock( &pluginMutex ); qDebug("close"); if ( audioScaleContext ) audio_resample_close( audioScaleContext ); if ( audioCodecContext ) avcodec_close( audioCodecContext ); if ( videoCodecContext ) avcodec_close( videoCodecContext ); if ( streamContext ) av_close_input_file( streamContext ); audioCodecContext = 0; videoCodecContext = 0; audioScaleContext = 0; streamContext = 0; fileLength = 0; bufferedSamplesCount = 0; openFlag = FALSE; return TRUE; } return FALSE;}bool LibFFMpegPlugin::isOpen(){ return openFlag;}int LibFFMpegPlugin::audioStreams(){ return (audioCodecContext) ? 1 : 0;}int LibFFMpegPlugin::audioChannels( int ){ return 2;}int LibFFMpegPlugin::audioFrequency( int ){ return 44100;}int LibFFMpegPlugin::audioSamples( int ){ return -1;}bool LibFFMpegPlugin::audioSetSample( long, int ){ return FALSE;}long LibFFMpegPlugin::audioGetSample( int ){ return 0;}bool LibFFMpegPlugin::audioReadSamples( short *output, int channels, long samples, long& samplesRead, int ){ AutoLockUnlockMutex lock( &audioMutex ); if ( !audioCodecContext || !audioCodecContext->codec ) { qDebug("No audio decoder for stream"); samplesRead = 0; return FALSE; } if ( samples > AVCODEC_MAX_AUDIO_FRAME_SIZE ) { qDebug("Decoder can not buffer that much data at a time!!!"); samples = AVCODEC_MAX_AUDIO_FRAME_SIZE; } uchar tmpSamples[AVCODEC_MAX_AUDIO_FRAME_SIZE * 8]; long long tmpSamplesRead = 0; long long fact = audioCodecContext->sample_rate * 2 * audioCodecContext->channels; long long bufferedSamplesCount_fact = bufferedSamplesCount * fact; long long samples_fact = samples * fact; // Buffer ahead long long tmpBufCount = bufferedSamplesCount_fact; bool haveBothTimeStamps = ( currentVideoTimeStamp && currentAudioTimeStamp ); if ( !haveBothTimeStamps ) samples_fact += 9200 * fact; // With DivX AVI streams I have tested against, libavcodec doesn't // return any time stamps and the audio needs to be slightly behind the video so buffering longer achieves this. while ( tmpBufCount < samples_fact ) { MediaPacket *pkt = getAnotherPacket( audioStream ); if ( !pkt ) { samplesRead = -1; return FALSE; // EOF } int len = pkt->pkt.size; unsigned char *ptr = pkt->pkt.data; int bytesRead = 0; while ( len ) { int ret = 0; if ( pkt ) { if ( ptr < pkt->pkt.data ) { qDebug("inconsistancy error");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -