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