diff --git a/src/avdecoder.cpp b/src/avdecoder.cpp index 42156d1..2f70bff 100644 --- a/src/avdecoder.cpp +++ b/src/avdecoder.cpp @@ -17,6 +17,7 @@ * along with this program. If not, see . */ +#include "utils.h" #include "avdecoder.h" #include "cmaobject.h" @@ -28,70 +29,49 @@ AVDecoder::AvInit init; AVDecoder::AVDecoder() : - pFormatCtx(NULL), pCodecCtx(NULL), file(NULL) + pFormatCtx(NULL), pCodecCtx(NULL), av_stream(NULL), av_codec(NULL), stream_index(-1) { } AVDecoder::~AVDecoder() { + if(pCodecCtx) { + avcodec_close(pCodecCtx); + } if(pFormatCtx) { - av_free(pFormatCtx->pb->buffer); - av_free(pFormatCtx->pb); avformat_close_input(&pFormatCtx); } - if(file) { - file->close(); - delete file; - } -} - -int AVDecoder::readFunction(void* opaque, uint8_t* buf, int buf_size) -{ - QIODevice* stream = (QIODevice*)opaque; - int numBytes = stream->read((char*)buf, buf_size); - return numBytes; -} - -int64_t AVDecoder::seekFunction(void* opaque, int64_t offset, int whence) -{ - if (whence == AVSEEK_SIZE) { - return -1; // I don't know "size of my handle in bytes" - } - QIODevice* stream = (QIODevice*)opaque; - if (stream->isSequential()) { - return -1; // cannot seek a sequential stream - } - if (! stream->seek(offset) ) { - return -1; - } - return stream->pos(); } bool AVDecoder::open(const QString filename) { - file = new QFile(filename); - if(!file->open(QIODevice::ReadOnly)) { - return false; - } - const int ioBufferSize = 32768; - unsigned char *ioBuffer = (unsigned char *)av_malloc(ioBufferSize + FF_INPUT_BUFFER_PADDING_SIZE); - AVIOContext *avioContext = avio_alloc_context(ioBuffer, ioBufferSize, 0, (void*)(file), &AVDecoder::readFunction, NULL, &AVDecoder::seekFunction); - pFormatCtx = avformat_alloc_context(); - pFormatCtx->pb = avioContext; - - - if(avformat_open_input(&pFormatCtx, "dummy", NULL, NULL) != 0) { - av_free(avioContext->buffer); - av_free(avioContext); + if(avformat_open_input(&pFormatCtx, QFile::encodeName(filename).constData(), NULL, NULL) != 0) { return false; } if(avformat_find_stream_info(pFormatCtx, NULL) < 0) { - av_free(avioContext->buffer); - av_free(avioContext); avformat_close_input(&pFormatCtx); return false; } + + return true; +} + +bool AVDecoder::loadCodec(codec_type codec) +{ + AVDictionary *opts = NULL; + + if((stream_index = av_find_best_stream(pFormatCtx, (AVMediaType)codec, -1, -1, &av_codec, 0)) < 0) { + return false; + } + + av_stream = pFormatCtx->streams[stream_index]; + pCodecCtx = av_stream->codec; + + if(avcodec_open2(pCodecCtx, av_codec, &opts) < 0) { + return false; + } + return true; } @@ -107,66 +87,32 @@ const char *AVDecoder::getMetadataEntry(const char *key, const char *default_val void AVDecoder::getAudioMetadata(metadata_t &metadata) { - AVDictionaryEntry *entry; - AVDictionary* file_metadata = pFormatCtx->metadata; + metadata.data.music.artist = strdup(getMetadataEntry("artist", "")); + metadata.data.music.album = strdup(getMetadataEntry("album", "")); + metadata.data.music.title = strdup(getMetadataEntry("title", "")); - if((entry = av_dict_get(file_metadata, "artist", NULL, 0)) != NULL) { - metadata.data.music.artist = strdup(entry->value); + if(loadCodec(CODEC_AUDIO)) { + metadata.data.music.tracks->data.track_audio.bitrate = pCodecCtx->bit_rate; } else { - metadata.data.music.artist = strdup(""); + metadata.data.music.tracks->data.track_audio.bitrate = pFormatCtx->bit_rate; } - - if((entry = av_dict_get(file_metadata, "album", NULL, 0)) != NULL) { - metadata.data.music.album = strdup(entry->value); - } else { - metadata.data.music.album = strdup(""); - } - - if((entry = av_dict_get(file_metadata, "title", NULL, 0)) != NULL) { - metadata.data.music.title = strdup(entry->value); - } else { - metadata.data.music.title = strdup(""); - } - - metadata.data.music.tracks->data.track_audio.bitrate = pFormatCtx->bit_rate; } void AVDecoder::getVideoMetadata(metadata_t &metadata) { - AVDictionaryEntry *entry; - AVDictionary* file_metadata = pFormatCtx->metadata; + metadata.data.video.copyright = strdup(getMetadataEntry("copyright", "")); + metadata.data.video.explanation = strdup(getMetadataEntry("comments", "")); + metadata.data.video.title = strdup(getMetadataEntry("title", metadata.name)); - if((entry = av_dict_get(file_metadata, "copyright", NULL, 0)) != NULL) { - metadata.data.video.copyright = strdup(entry->value); - } else { - metadata.data.video.copyright = strdup(""); - } - - if((entry = av_dict_get(file_metadata, "comments", NULL, 0)) != NULL) { - metadata.data.video.explanation = strdup(entry->value); - } else { - metadata.data.video.explanation = strdup(""); - } - - if((entry = av_dict_get(file_metadata, "title", NULL, 0)) != NULL) { - metadata.data.video.title = strdup(entry->value); - } else { - metadata.data.video.title = strdup(metadata.name); - } - - metadata.data.video.tracks->data.track_video.duration = pFormatCtx->duration / 1000; - metadata.data.video.tracks->data.track_video.bitrate = pFormatCtx->bit_rate; - - int stream_index; - AVCodec *codec = NULL; - - if((stream_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0)) >= 0) { - AVCodecContext *pCodecCtx = pFormatCtx->streams[stream_index]->codec; + if(loadCodec(CODEC_VIDEO)) { metadata.data.video.tracks->data.track_video.width = pCodecCtx->width; metadata.data.video.tracks->data.track_video.height = pCodecCtx->height; - if(strcmp(codec->name, "h264") == 0) { + metadata.data.video.tracks->data.track_video.bitrate = pCodecCtx->bit_rate; + metadata.data.video.tracks->data.track_video.duration = pFormatCtx->duration / 1000; + + if(strcmp(av_codec->name, "h264") == 0) { metadata.data.video.tracks->data.track_video.codecType = CODEC_TYPE_AVC; - } else if(strcmp(codec->name, "mpeg4") == 0) { + } else if(strcmp(av_codec->name, "mpeg4") == 0) { metadata.data.video.tracks->data.track_video.codecType = CODEC_TYPE_MPEG4; } else { metadata.data.video.tracks->data.track_video.codecType = 0; @@ -174,50 +120,11 @@ void AVDecoder::getVideoMetadata(metadata_t &metadata) } } -int AVDecoder::getWidth() -{ - return pCodecCtx->width; -} - -int AVDecoder::getHeight() -{ - return pCodecCtx->height; -} - -int AVDecoder::getDuration() -{ - return pFormatCtx->duration / 1000; -} - -int AVDecoder::getBitrate() -{ - return pFormatCtx->bit_rate; -} - -int AVDecoder::getCodecBitrate() -{ - return pCodecCtx->bit_rate; -} - -bool AVDecoder::loadCodec(codec_type codec) -{ - int stream_index = av_find_best_stream(pFormatCtx, (AVMediaType)codec, -1, -1, NULL, 0); - if(stream_index >= 0) { - pCodecCtx = pFormatCtx->streams[stream_index]->codec; - return true; - } else { - return false; - } -} - QByteArray AVDecoder::getAudioThumbnail(int width, int height) { QByteArray data; - int stream_index; - AVCodec *codec = NULL; - if((stream_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0)) < 0) { - // no thumbnail + if(!loadCodec(CODEC_VIDEO)) { return data; } @@ -259,27 +166,16 @@ AVFrame *AVDecoder::getDecodedFrame(AVCodecContext *pCodecCtx, int stream_index) QByteArray AVDecoder::getVideoThumbnail(int width, int height) { QByteArray data; - int stream_index; AVFrame *pFrame; - AVDictionary *opts = NULL; - AVCodec *codec = NULL; - AVCodecContext *pCodecCtx = NULL; int percentage = QSettings().value("videoThumbnailSeekPercentage", 30).toInt(); - if((stream_index = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0)) < 0) { - return data; - } - - pCodecCtx = pFormatCtx->streams[stream_index]->codec; - - if(avcodec_open2(pCodecCtx, codec, &opts) < 0) { - avcodec_close(pCodecCtx); + if(!loadCodec(CODEC_VIDEO)) { return data; } qint64 seek_pos = pFormatCtx->duration * percentage / (AV_TIME_BASE * 100); - qint64 frame = av_rescale(seek_pos,pFormatCtx->streams[stream_index]->time_base.den, pFormatCtx->streams[stream_index]->time_base.num); + qint64 frame = av_rescale(seek_pos, av_stream->time_base.den, av_stream->time_base.num); if(avformat_seek_file(pFormatCtx, stream_index, 0, frame, frame, AVSEEK_FLAG_FRAME) < 0) { avcodec_close(pCodecCtx); @@ -348,10 +244,6 @@ QByteArray AVDecoder::getVideoThumbnail(int width, int height) void AVDecoder::close() { - av_free(pFormatCtx->pb->buffer); - av_free(pFormatCtx->pb); avformat_close_input(&pFormatCtx); pFormatCtx = NULL; - file->close(); - file = NULL; } diff --git a/src/avdecoder.h b/src/avdecoder.h index 1e6d866..2797c2b 100644 --- a/src/avdecoder.h +++ b/src/avdecoder.h @@ -20,7 +20,6 @@ #ifndef AVDECODER_H #define AVDECODER_H -#include #include #include @@ -51,11 +50,21 @@ public: void getVideoMetadata(metadata_t &metadata); const char *getMetadataEntry(const char *key, const char *default_value = NULL); - int getWidth(); - int getHeight(); - int getDuration(); - int getBitrate(); - int getCodecBitrate(); + inline int getWidth() { + return pCodecCtx->width; + } + + inline int getHeight() { + return pCodecCtx->height; + } + + inline int getDuration() { + return pFormatCtx->duration / 1000; + } + + inline int getBitrate() { + return pCodecCtx->bit_rate; + } // simulate a static constructor to initialize libav only once class AvInit @@ -63,21 +72,21 @@ public: public: AvInit() { av_register_all(); + // hide warning logs + av_log_set_level(AV_LOG_ERROR); } }; static AvInit init; private: - void AVFrameToQImage(AVFrame &frame, QImage &image, int width, int height); AVFrame *getDecodedFrame(AVCodecContext *pCodecCtx, int stream_index); - static int readFunction(void* opaque, uint8_t* buf, int buf_size); - static int64_t seekFunction(void* opaque, int64_t offset, int whence); - AVFormatContext *pFormatCtx; AVCodecContext *pCodecCtx; - QFile *file; + AVStream *av_stream; + AVCodec *av_codec; + int stream_index; }; #endif // AVDECODER_H