📄 libffmpegplugin.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 <qfileinfo.h>#include "libffmpegplugin.h"LibFFMpegPlugin::LibFFMpegPlugin() : videoContext(&packetBuffer), audioContext(&packetBuffer){ FFAutoLockUnlockMutex lock(pluginMutex); strInfo = ""; streamingFlag = FALSE; needPluginInit = TRUE;}LibFFMpegPlugin::~LibFFMpegPlugin(){ // qDebug("LibFFMpegPlugin::~LibFFMpegPlugin()"); close(); // qDebug("LibFFMpegPlugin::~LibFFMpegPlugin() finished");}bool LibFFMpegPlugin::isFileSupported( const QString& fileName ){ qDebug("Checking if %s is supported", fileName.latin1() ); QString ext2 = fileName.right(3).lower(); QString ext3 = fileName.right(4).lower(); QString ext4 = fileName.right(5).lower(); if ( ( ext3 == ".asf" ) || ( ext3 == ".amr" ) || ( ext3 == ".avi" ) || //( ext3 == ".ogg" ) || ( ext3 == ".vob" ) || ( ext3 == ".wav" ) || ( ext3 == ".mov" ) || ( ext3 == ".mp2" ) || ( ext3 == ".mp3" ) || ( ext3 == ".mp4" ) || ( ext4 == ".mpeg") || ( ext3 == ".mpg" ) || ( ext2 == ".rm" ) || ( ext3 == ".wma" ) || ( ext3 == ".wmf" ) || ( ext3 == ".wmv" )) return true; // Wav files need to be handled by the wav plugin if ( ext3 == ".wav" ) return false; bool okay = open( fileName ); close(); return okay;}bool LibFFMpegPlugin::open( const QString& fileName ){ if ( !init( fileName ) ) return false; return true;}bool LibFFMpegPlugin::openURL( const QUrl& url, const QString& ){ if ( !init(url.toString(false, false)) ) return false; FFAutoLockUnlockMutex lock(pluginMutex); streamingFlag = true; return true;}bool LibFFMpegPlugin::init( const QString& fileName ){ FFAutoLockUnlockMutex lock(pluginMutex); qDebug("LibFFMpegPlugin::init()"); if ( needPluginInit ) { avcodec_init(); avcodec_register_all(); av_register_all(); needPluginInit = false; } fileLength = 0; totalTimeCache = 0; haveTotalTimeCache = false; streamingFlag = false; strInfo = ""; savedSeekPos.assign(-1); packetBuffer.init(); videoContext.fileInit(); audioContext.fileInit(); if (!packetBuffer.open(fileName)) return false; audioContext.codecInit(); videoContext.codecInit(); // Get the file length fileLength = packetBuffer.fileLength(); // Get the total bit rate totalBitRate = packetBuffer.bitRate(); if ( !totalBitRate ) { // Add together the audio and video bit rates long audioBitRate = audioContext.bitRate(); long videoBitRate = videoContext.bitRate(); if ( audioStreams() && audioBitRate > 0 ) totalBitRate += audioBitRate; if ( videoStreams() && videoBitRate > 0 ) totalBitRate += videoBitRate; } haveTotalBitRate = (bool)totalBitRate; // Get the total time totalTimeCache = packetBuffer.duration(); if ( !totalTimeCache ) { if ( totalBitRate && fileLength ) { // 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)fileLength * 8000) / totalBitRate; } }#if FIND_LAST_PACKET_TIMESTAMP_TO_WORK_OUT_PLAY_TIME // Last resort attempt to determine the total play time // Seeks towards the end of the file, reads packets looking for timestamps if ( !totalTimeCache ) totalTimeCache = packetBuffer.getLastPacketTime();#endif haveTotalTimeCache = (bool)totalTimeCache; qDebug(" File length: %li bytes", fileLength); qDebug(" Total time: %li ms", totalTimeCache); qDebug(" Total bitrate: %li bits/sec", totalBitRate); qDebug("LibFFMpegPlugin::init() finished");// packetBuffer.start(); return true;}const QString &LibFFMpegPlugin::fileInfo(){ FFAutoLockUnlockMutex lock(pluginMutex); if ( strInfo == "" ) { if ( haveTotalTimeCache ) { int seconds = totalTimeCache / 1000; strInfo += qApp->translate( "LibFFMpegPlugin", "Length: " ) + QString::number( seconds / 60 ) + ":" + QString::number( (seconds % 60) / 10 ) + QString::number( (seconds % 60) % 10 ) + ","; } strInfo += audioContext.fileInfo(); strInfo += videoContext.fileInfo(); } return strInfo;}bool LibFFMpegPlugin::close(){ qDebug("LibFFMpegPlugin::close()"); FFAutoLockUnlockMutex lock(pluginMutex); flushBuffers(); if ( packetBuffer.isOpen() ) { fileLength = 0; audioContext.close(); videoContext.close(); packetBuffer.close(); return TRUE; } return FALSE;}bool LibFFMpegPlugin::audioReadSamples( short *output, int channels, long samples, long& samplesRead, int ){/* qDebug("LibFFMpegPlugin::audioReadSamples() decoded pts, video: %5li audio: %5li faked pts, video: %5li audio: %5li", videoContext.absoluteTimeStamp(), audioContext.absoluteTimeStamp(), videoContext.timeStamp(), audioContext.timeStamp());*/ return (realSeek()) ? audioContext.audioReadSamples(output, channels, samples, samplesRead) : false;}bool LibFFMpegPlugin::videoReadScaledFrame( unsigned char **output_rows, int, int, int in_w, int in_h, int out_w, int out_h, ColorFormat fmt, int ){/* qDebug("LibFFMpegPlugin::videoReadScaledFrame() decoded pts, video: %5li audio: %5li faked pts, video: %5li audio: %5li", videoContext.absoluteTimeStamp(), audioContext.absoluteTimeStamp(), videoContext.timeStamp(), audioContext.timeStamp());*/ return (realSeek()) ? videoContext.videoReadScaledFrame(output_rows, in_w, in_h, out_w, out_h, fmt) : 1;}bool LibFFMpegPlugin::sync(){ if ( realSeek() && packetBuffer.isOpen() && audioStreams() && videoStreams() ) return videoContext.syncToTimeStamp(audioContext.timeStamp()); // relative time stamp //qDebug("sync needs both audio and video contexts to sync together"); return false;}bool LibFFMpegPlugin::seek( long pos ){ qDebug("LibFFMpegPlugin::seek()"); FFAutoLockUnlockMutex lock(pluginMutex); if ( pos > 1000 ) pos = pos - 1000; else pos = 0; savedSeekPos.assign(pos); qDebug("LibFFMpegPlugin::seek() finished"); return true;}//// Seek and realSeek are split in two because realSeek can take a reasonable// amount of CPU when both video and audio are involved.// The mediaplayer calls seek as the user moves the slider, and as they// move the slider it updates the UI with where in the file they are.// This is queried with a call to currentTime()//bool LibFFMpegPlugin::realSeek(){ // throw away any outstanding packets we aren't consuming if ( !audioStreams() ) packetBuffer.flushAudioPackets(); if ( !videoStreams() ) packetBuffer.flushVideoPackets(); if ( savedSeekPos == -1 ) return true; FFAutoLockUnlockMutex lock(pluginMutex); long pos = (int)savedSeekPos; savedSeekPos.assign(-1); // Seek in to the file if ( packetBuffer.seek(pos) ) { if ( videoStreams() ) { videoContext.leadInVideo(); if ( audioStreams() ) // Throw away audio packets till they are in time with the video packets audioContext.syncToTimeStamp(videoContext.absoluteTimeStamp()); // absolute value } if ( audioStreams() ) { audioContext.leadInAudio(); if ( videoStreams() ) videoContext.syncToTimeStamp(audioContext.absoluteTimeStamp()); } return true; } // qDebug("LibFFMpegPlugin::realSeek() finished"); return false;}long LibFFMpegPlugin::tell(){ if (savedSeekPos != -1) return (int)savedSeekPos; return packetBuffer.pos();}bool LibFFMpegPlugin::currentTimeAvailable(){ // Use audio context first, using its lock long audioTimeStamp = audioContext.absoluteTimeStamp(); if (audioTimeStamp != -1) return true; // Then seperately lock plugin without audio context locked FFAutoLockUnlockMutex lock(pluginMutex); return (totalBitRate || (fileLength && haveTotalTimeCache));}long LibFFMpegPlugin::currentTime(){ // qDebug("LibFFMpegPlugin::currentTime"); // Use audio context first, using its lock long audioTimeStamp = audioContext.absoluteTimeStamp(); if ( audioTimeStamp != -1 ) { if (savedSeekPos == -1) { // qDebug("LibFFMpegPlugin::currentTime end"); return audioTimeStamp; } } FFAutoLockUnlockMutex lock(pluginMutex); if ( fileLength && haveTotalTimeCache ) { // This method is generally more accurate, try it before using the bitrate method return ((long long)totalTimeCache * tell()) / fileLength; } else 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. return ((long long)8000 * tell()) / totalBitRate; } return -1;}//// Only calls thread safe functions//void LibFFMpegPlugin::flushBuffers(){ audioContext.flush(); videoContext.flush(); packetBuffer.flush();}//// Thread safe assuming QString and QUrl functions don't make use of static or global variables.// Also shouldn't be a problem as this function in reality is only called before decoding// starts always from the main thread//bool LibFFMpegPlugin::canStreamURL( const QUrl& url, const QString& ){ QString fileName = url.toString( true, false ); // Support file:// if ( fileName.left(7).lower() == "file://" ) return true; // Support http:// if ( fileName.left(7).lower() == "http://" ) return true; // Support rtsp:// if ( fileName.left(7).lower() == "rtsp://" ) return true; // Does not support mms:// if ( fileName.left(6).lower() == "mms://" ) return false; // All others assumed not supported return false;}bool LibFFMpegPlugin::streamed(){ FFAutoLockUnlockMutex lock(pluginMutex); return streamingFlag;}bool LibFFMpegPlugin::lengthAvailable(){ FFAutoLockUnlockMutex lock(pluginMutex); return !streamingFlag;}long LibFFMpegPlugin::length(){ FFAutoLockUnlockMutex lock(pluginMutex); return fileLength;}bool LibFFMpegPlugin::totalTimeAvailable(){ FFAutoLockUnlockMutex lock(pluginMutex); return haveTotalTimeCache;}long LibFFMpegPlugin::totalTime(){ FFAutoLockUnlockMutex lock(pluginMutex); return totalTimeCache;}bool LibFFMpegPlugin::seekAvailable(){ FFAutoLockUnlockMutex lock(pluginMutex); return !streamingFlag;}bool LibFFMpegPlugin::tellAvailable(){ FFAutoLockUnlockMutex lock(pluginMutex); return true;//!streamingFlag;}//// Clearly thread safe functions//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::isOpen(){ return packetBuffer.isOpen();}int LibFFMpegPlugin::audioStreams(){ return audioContext.audioStreams();}int LibFFMpegPlugin::audioChannels(int stream){ return audioContext.audioChannels(stream);}int LibFFMpegPlugin::audioFrequency(int stream){ return audioContext.audioFrequency(stream);}int LibFFMpegPlugin::audioSamples( int ){ return -1;}bool LibFFMpegPlugin::audioSetSample( long, int ){ return false;}long LibFFMpegPlugin::audioGetSample( int ){ return 0;}int LibFFMpegPlugin::videoStreams(){ return videoContext.videoStreams();}int LibFFMpegPlugin::videoWidth(int stream){ return videoContext.videoWidth(stream);}int LibFFMpegPlugin::videoHeight(int stream){ return videoContext.videoHeight(stream);}double LibFFMpegPlugin::videoFrameRate(int stream){ return videoContext.videoFrameRate(stream);}int LibFFMpegPlugin::videoFrames( int ){ return -1;}bool LibFFMpegPlugin::videoSetFrame( long, int ){ return false;}long LibFFMpegPlugin::videoGetFrame( int ){ return -1;}bool LibFFMpegPlugin::videoReadFrame( unsigned char **, int, int, int, int, ColorFormat, int ){ return false;}bool LibFFMpegPlugin::videoReadYUVFrame( char *, char *, char *, int, int, int, int, int ){ return false;}double LibFFMpegPlugin::getTime(){ return -1;}bool LibFFMpegPlugin::setSMP( int ){ return false;}bool LibFFMpegPlugin::setMMX( bool ){ return false;}bool LibFFMpegPlugin::supportsAudio(){ return true;}bool LibFFMpegPlugin::supportsVideo(){ return true;}bool LibFFMpegPlugin::supportsYUV(){ return false;}bool LibFFMpegPlugin::supportsMMX(){ return false;}bool LibFFMpegPlugin::supportsSMP(){ return false;}bool LibFFMpegPlugin::supportsStereo(){ return true;}bool LibFFMpegPlugin::supportsScaling(){ return true;}long LibFFMpegPlugin::getPlayTime(){ return -1;}bool LibFFMpegPlugin::supportsStreaming(){ return true;}bool LibFFMpegPlugin::syncAvailable(){ return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -