Skip to content

Commit

Permalink
Added support for loading media from a QIODevice.
Browse files Browse the repository at this point in the history
  • Loading branch information
sladage committed Jan 30, 2014
1 parent e4df334 commit 96c22e3
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 8 deletions.
70 changes: 69 additions & 1 deletion src/AVDemuxer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <QtAV/AVError.h>
#include <QtAV/Packet.h>
#include <QtAV/QtAV_Compat.h>
#include <QtAV/QAVIOContext.h>
#include <QtCore/QThread>
#include <QtCore/QCoreApplication>

Expand Down Expand Up @@ -135,6 +136,7 @@ AVDemuxer::AVDemuxer(const QString& fileName, QObject *parent)
, mSeekUnit(SeekByTime)
, mSeekTarget(SeekTarget_AnyFrame)
, mpDict(0)
, m_pQAVIO(0)
{
mpInterrup = new InterruptHandler(this);
if (!_file_name.isEmpty())
Expand Down Expand Up @@ -371,7 +373,7 @@ void AVDemuxer::seek(qreal q)
*/
bool AVDemuxer::isLoaded(const QString &fileName) const
{
return fileName == _file_name && (a_codec_context || v_codec_context || s_codec_contex);
return (fileName == _file_name || m_pQAVIO) && (a_codec_context || v_codec_context || s_codec_contex);
}

bool AVDemuxer::loadFile(const QString &fileName)
Expand Down Expand Up @@ -445,6 +447,72 @@ bool AVDemuxer::loadFile(const QString &fileName)
return true;
}

bool AVDemuxer::load(QAVIOContext* iocon)
{
class AVInitializer {
public:
AVInitializer() {
qDebug("av_register_all and avformat_network_init");
av_register_all();
avformat_network_init();
}
~AVInitializer() {
qDebug("avformat_network_deinit");
avformat_network_deinit();
}
};
static AVInitializer sAVInit;
Q_UNUSED(sAVInit);
close();
qDebug("all closed and reseted");

//alloc av format context
if (!format_context)
format_context = avformat_alloc_context();
format_context->pb = iocon->context();
//format_context->pb = avio_alloc_context(iocon->m_ucDataBuffer,IODATA_BUFFER_SIZE,0,iocon,&iocon->read,0,&iocon->seek);
//format_context->flags |= AVFMT_FLAG_GENPTS | AVFMT_FLAG_CUSTOM_IO;
format_context->flags = AVFMT_FLAG_CUSTOM_IO;

//install interrupt callback
format_context->interrupt_callback = *mpInterrup;

qDebug("avformat_open_input: format_context:'%p'...",format_context);

mpInterrup->begin(InterruptHandler::Open);
int ret = avformat_open_input(&format_context, "iodevice", NULL, mOptions.isEmpty() ? NULL : &mpDict);
mpInterrup->end();

qDebug("avformat_open_input: (with io device) ret:%d", ret);

if (ret < 0) {
//if (avformat_open_input(&format_context, qPrintable(filename), NULL, NULL)) {
AVError err(AVError::OpenError, ret);
emit error(err);
qWarning("Can't open media: %s", qPrintable(err.string()));
return false;
}
//deprecated
//if(av_find_stream_info(format_context)<0) {
//TODO: avformat_find_stream_info is too slow, only useful for some video format
mpInterrup->begin(InterruptHandler::FindStreamInfo);
ret = avformat_find_stream_info(format_context, NULL);
mpInterrup->end();
if (ret < 0) {
AVError err(AVError::FindStreamInfoError, ret);
emit error(err);
qWarning("Can't find stream info: %s", qPrintable(err.string()));
return false;
}

if (!prepareStreams()) {
return false;
}

started_ = false;
return true;
}

bool AVDemuxer::prepareStreams()
{
if (!findStreams())
Expand Down
33 changes: 28 additions & 5 deletions src/AVPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
#include <QtAV/AudioOutputTypes.h>
#include <QtAV/FilterManager.h>

#include <QtAV/QAVIOContext.h>

namespace QtAV {

static const int kPosistionCheckMS = 500;
Expand All @@ -73,6 +75,8 @@ AVPlayer::AVPlayer(QObject *parent) :
{
formatCtx = 0;
last_position = 0;

m_pQAVIO = 0;
/*
* must be the same value at the end of stop(), and must be different from value in
* stopFromDemuxerThread()(which is false), so the initial value must be true
Expand Down Expand Up @@ -154,6 +158,8 @@ AVPlayer::~AVPlayer()
delete demuxer_thread;
demuxer_thread = 0;
}
if (m_pQAVIO)
delete m_pQAVIO;
}

AVClock* AVPlayer::masterClock()
Expand Down Expand Up @@ -449,6 +455,13 @@ QString AVPlayer::file() const
return path;
}

void AVPlayer::setIODevice(QIODevice* device)
{
if (isLoaded())
return;
m_pQAVIO = new QAVIOContext(device);
}

VideoCapture* AVPlayer::videoCapture()
{
return video_capture;
Expand Down Expand Up @@ -521,8 +534,8 @@ bool AVPlayer::load(const QString &path, bool reload)
bool AVPlayer::load(bool reload)
{
loaded = false;
if (path.isEmpty()) {
qDebug("No file to load...");
if (path.isEmpty() && !m_pQAVIO) {
qDebug("No file or IODevice was set.");
return false;
}
// release codec ctx
Expand All @@ -532,7 +545,10 @@ bool AVPlayer::load(bool reload)
if (video_dec) {
video_dec->setCodecContext(0);
}
qDebug("loading: %s ...", path.toUtf8().constData());
if (!m_pQAVIO)
qDebug("Loading from IODevice...");
else
qDebug("loading: %s ...", path.toUtf8().constData());
if (reload || !demuxer.isLoaded(path)) {
//close decoders here to make sure open and close in the same thread
if (audio_dec && audio_dec->isOpen()) {
Expand All @@ -541,8 +557,15 @@ bool AVPlayer::load(bool reload)
if (video_dec && video_dec->isOpen()) {
video_dec->close();
}
if (!demuxer.loadFile(path)) {
return false;
if (!m_pQAVIO)
{
if (!demuxer.loadFile(path))
return false;
}
else
{
if (!demuxer.load(m_pQAVIO))
return false;
}
} else {
demuxer.prepareStreams();
Expand Down
63 changes: 63 additions & 0 deletions src/QAVIOContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <QtAV/QAVIOContext.h>
#include <QIODevice>
#include <QtAV/QtAV_Compat.h>
#include <QDebug>

namespace QtAV {

QAVIOContext::QAVIOContext(QIODevice *io) : m_pIO(io)
{
m_ucDataBuffer = new unsigned char[IODATA_BUFFER_SIZE];
}

QAVIOContext::~QAVIOContext()
{
delete m_ucDataBuffer;
}

int QAVIOContext::read(void *opaque, unsigned char *buf, int buf_size)
{
QAVIOContext* avio = static_cast<QAVIOContext*>(opaque);
//qDebug() << "read" << buf_size << avio->m_pIO->pos() << IODATA_BUFFER_SIZE;
return avio->m_pIO->read((char*)buf,buf_size);
}

int QAVIOContext::write(void *opaque, unsigned char *buf, int buf_size)
{
QAVIOContext* avio = static_cast<QAVIOContext*>(opaque);
//qDebug() << "write";
return avio->m_pIO->write((char*)buf,buf_size);
}

int64_t QAVIOContext::seek(void *opaque, int64_t offset, int whence)
{
QAVIOContext* avio = static_cast<QAVIOContext*>(opaque);
//qDebug() << "seek";
int i = 0;

if (whence == SEEK_END)
{
offset = avio->m_pIO->size() - offset;
}
else if (whence == SEEK_CUR)
{
offset = avio->m_pIO->pos() + offset;
}
else if (whence == AVSEEK_SIZE)
{
return avio->m_pIO->size();
}

if (!avio->m_pIO->seek(offset))
i=-1;
else
i=offset;
return i;
}

AVIOContext* QAVIOContext::context()
{
return avio_alloc_context(m_ucDataBuffer,IODATA_BUFFER_SIZE,0,this,&read,0,&seek);
}

}
4 changes: 4 additions & 0 deletions src/QtAV/AVDemuxer.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ namespace QtAV {

class AVError;
class Packet;
class QAVIOContext;

class Q_AV_EXPORT AVDemuxer : public QObject //QIODevice?
{
Q_OBJECT
Expand Down Expand Up @@ -74,6 +76,7 @@ class Q_AV_EXPORT AVDemuxer : public QObject //QIODevice?
bool close();
bool loadFile(const QString& fileName);
bool isLoaded(const QString& fileName) const;
bool load(QAVIOContext* iocontext);
bool prepareStreams(); //called by loadFile(). if change to a new stream, call it(e.g. in AVPlayer)

void putFlushPacket();
Expand Down Expand Up @@ -206,6 +209,7 @@ class Q_AV_EXPORT AVDemuxer : public QObject //QIODevice?
AVCodecContext *a_codec_context, *v_codec_context, *s_codec_contex;
//copy the info, not parse the file when constructed, then need member vars
QString _file_name;
QAVIOContext* m_pQAVIO;
QMutex mutex; //for seek and readFrame
QElapsedTimer seek_timer;

Expand Down
7 changes: 7 additions & 0 deletions src/QtAV/AVPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class AVDemuxThread;
class Filter;
class VideoCapture;
class OutputSet;
class QAVIOContext;
class Q_AV_EXPORT AVPlayer : public QObject
{
Q_OBJECT
Expand All @@ -65,6 +66,10 @@ class Q_AV_EXPORT AVPlayer : public QObject
// If path is different from previous one, the stream to play will be reset to default.
void setFile(const QString& path);
QString file() const;

//QIODevice support
void setIODevice(QIODevice* device);

// force reload even if already loaded. otherwise only reopen codecs if necessary
bool load(const QString& path, bool reload = true);
bool load(bool reload = true);
Expand Down Expand Up @@ -294,6 +299,8 @@ private slots:
int repeat_max, repeat_current;
int timer_id; //notify position change and check AB repeat range. active when playing

QAVIOContext *m_pQAVIO;

//the following things are required and must be set not null
AVDemuxer demuxer;
AVDemuxThread *demuxer_thread;
Expand Down
32 changes: 32 additions & 0 deletions src/QtAV/QAVIOContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef AVIOCONTEXT_H
#define AVIOCONTEXT_H

#include <sys/types.h>
#include <QtAV_Global.h>

class QIODevice;
struct AVIOContext;

#define IODATA_BUFFER_SIZE 32768

namespace QtAV {

class QAVIOContext
{
public:
QAVIOContext(QIODevice* io);
~QAVIOContext();
static int read(void *opaque, unsigned char *buf, int buf_size);
static int write(void *opaque, unsigned char *buf, int buf_size);
static int64_t seek(void *opaque, int64_t offset, int whence);

AVIOContext* context();

QIODevice* m_pIO;

//private:
unsigned char* m_ucDataBuffer;
};

}
#endif // AVIOCONTEXT_H
6 changes: 4 additions & 2 deletions src/libQtAV.pro
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ SOURCES += \
VideoDecoderTypes.cpp \
VideoDecoderFFmpeg.cpp \
VideoDecoderFFmpegHW.cpp \
VideoThread.cpp
VideoThread.cpp \
QAVIOContext.cpp

SDK_HEADERS *= \
QtAV/QtAV.h \
Expand Down Expand Up @@ -244,7 +245,8 @@ HEADERS *= \
QtAV/private/VideoDecoderFFmpegHW_p.h \
QtAV/private/VideoRenderer_p.h \
QtAV/private/QPainterRenderer_p.h \
QtAV/private/WidgetRenderer_p.h
QtAV/private/WidgetRenderer_p.h \
QtAV/QAVIOContext.h


SDK_INCLUDE_FOLDER = QtAV
Expand Down

0 comments on commit 96c22e3

Please sign in to comment.