From 75f7d7040cc6ac310b5111a5a6d96f44c630053a Mon Sep 17 00:00:00 2001 From: wang-bin Date: Fri, 18 Oct 2013 00:59:40 +0800 Subject: [PATCH] new AVDecoder api --- src/AVDecoder.cpp | 95 ++++++++++++++++++++++++++++++++-- src/AVDemuxer.cpp | 23 ++++---- src/QtAV/AVDecoder.h | 12 ++++- src/QtAV/AVDemuxer.h | 6 ++- src/QtAV/private/AVDecoder_p.h | 5 +- 5 files changed, 122 insertions(+), 19 deletions(-) diff --git a/src/AVDecoder.cpp b/src/AVDecoder.cpp index dd3f1a1b6..3e4d6b336 100644 --- a/src/AVDecoder.cpp +++ b/src/AVDecoder.cpp @@ -37,6 +37,78 @@ AVDecoder::~AVDecoder() { } +bool AVDecoder::open() +{ + DPTR_D(AVDecoder); + if (!d.codec_ctx) { + qWarning("FFmpeg codec context not ready"); + return false; + } + AVCodec *codec = 0; + if (!d.name.isEmpty()) { + codec = avcodec_find_decoder_by_name(d.name.toUtf8().constData()); + } else { + codec = avcodec_find_decoder(d.codec_ctx->codec_id); + } + if (!codec) { + if (d.name.isEmpty()) { + qWarning("No codec could be found with id %d", d.codec_ctx->codec_id); + } else { + qWarning("No codec could be found with name %s", d.name.toUtf8().constData()); + } + return false; + } + + //setup codec context + if (d.low_resolution > codec->max_lowres) { + qWarning("Use the max value for lowres supported by the decoder (%d)", codec->max_lowres); + d.low_resolution = codec->max_lowres; + } + d.codec_ctx->lowres = d.low_resolution; + if (d.codec_ctx->lowres) { + d.codec_ctx->flags |= CODEC_FLAG_EMU_EDGE; + } + if (d.fast) { + d.codec_ctx->flags2 |= CODEC_FLAG2_FAST; + } else { + //d.codec_ctx->flags2 &= ~CODEC_FLAG2_FAST; //ffplay has no this + } + if (codec->capabilities & CODEC_CAP_DR1) { + d.codec_ctx->flags |= CODEC_FLAG_EMU_EDGE; + } + //set thread + if (d.threads == -1) + d.threads = qMax(0, QThread::idealThreadCount()); + if (d.threads > 0) + d.codec_ctx->thread_count = d.threads; + if (d.threads > 1) + d.codec_ctx->thread_type = d.thread_slice ? FF_THREAD_SLICE : FF_THREAD_FRAME; + + //set dict used by avcodec_open2(). see ffplay + // AVDictionary *opts; + int ret = avcodec_open2(d.codec_ctx, codec, NULL); + if (ret < 0) { + qWarning("open video codec failed: %s", av_err2str(ret)); + return false; + } + return true; +} + +bool AVDecoder::close() +{ + DPTR_D(AVDecoder); + if (!d.codec_ctx) { + qWarning("FFmpeg codec context not ready"); + return false; + } + int ret = avcodec_close(d.codec_ctx); + if (ret < 0) { + qWarning("failed to close decoder: %s", av_err2str(ret)); + return false; + } + return true; +} + void AVDecoder::flush() { if (isAvailable()) @@ -49,6 +121,7 @@ void AVDecoder::setCodecContext(AVCodecContext *codecCtx) d.codec_ctx = codecCtx; } +//TODO: reset other parameters? AVCodecContext* AVDecoder::codecContext() const { return d_func().codec_ctx; @@ -59,6 +132,17 @@ void AVDecoder::setLowResolution(int lowres) d_func().low_resolution = lowres; } +void AVDecoder::setCodecName(const QString &name) +{ + d_func().name = name; +} + +QString AVDecoder::codecName() const +{ + DPTR_D(const AVDecoder); + return d.name.isEmpty() ? d.codec_ctx->codec->name : d.name; +} + int AVDecoder::lowResolution() const { return d_func().low_resolution; @@ -67,8 +151,8 @@ int AVDecoder::lowResolution() const void AVDecoder::setDecodeThreads(int threads) { DPTR_D(AVDecoder); - d.threads = threads > 0 ? threads : QThread::idealThreadCount(); - d.threads = qMax(d.threads, 1); + d.threads = threads;// threads >= 0 ? threads : qMax(0, QThread::idealThreadCount()); + d.threads = qMax(d.threads, 0); //check max? } int AVDecoder::decodeThreads() const @@ -95,11 +179,12 @@ bool AVDecoder::prepare() } qDebug("Decoding threads count: %d", d.threads); #if DECODER_DONE //currently codec context is opened in demuxer, we must setup context before open - d.codec_ctx->thread_count = d.threads; + if (d.threads > 0) + d.codec_ctx->thread_count = d.threads; if (d.threads > 1) d.codec_ctx->thread_type = d.thread_slice ? FF_THREAD_SLICE : FF_THREAD_FRAME; - else - d.codec_ctx->thread_type = 0; //FF_THREAD_FRAME:1, FF_THREAD_SLICE:2 + //else + // d.codec_ctx->thread_type = 0; //FF_THREAD_FRAME:1, FF_THREAD_SLICE:2 //? !CODEC_ID_H264 && !CODEC_ID_VP8 d.codec_ctx->lowres = d.low_resolution; diff --git a/src/AVDemuxer.cpp b/src/AVDemuxer.cpp index bf04a926c..350205d6e 100644 --- a/src/AVDemuxer.cpp +++ b/src/AVDemuxer.cpp @@ -289,6 +289,7 @@ void AVDemuxer::seek(qreal q) //AVSEEK_FLAG_BACKWARD has no effect? because we know the timestamp // FIXME: back flag is opposite? otherwise seek is bad and may crash? int seek_flag = (backward ? 0 : AVSEEK_FLAG_BACKWARD); //AVSEEK_FLAG_ANY + //bool seek_bytes = !!(format_context->iformat->flags & AVFMT_TS_DISCONT) && strcmp("ogg", format_context->iformat->name); int ret = av_seek_frame(format_context, -1, t, seek_flag); //avformat_seek_file() #endif @@ -450,6 +451,8 @@ bool AVDemuxer::openCodecs() if (a_codec_context) { AVCodec *aCodec = avcodec_find_decoder(a_codec_context->codec_id); if (aCodec) { + if (aCodec->capabilities & CODEC_CAP_DR1) + a_codec_context->flags |= CODEC_FLAG_EMU_EDGE; ret = avcodec_open2(a_codec_context, aCodec, NULL); if (ret < 0) { _has_audio = false; @@ -478,15 +481,7 @@ bool AVDemuxer::openCodecs() _has_vedio = false; } ////v_codec_context->time_base = (AVRational){1,30}; - //avcodec_open(v_codec_context, vCodec) //deprecated - ret = avcodec_open2(v_codec_context, vCodec, NULL); - if (ret < 0) { - qWarning("open video codec failed: %s", av_err2str(ret)); - _has_vedio = false; - } else { - if (vCodec->capabilities & CODEC_CAP_DR1) - v_codec_context->flags |= CODEC_FLAG_EMU_EDGE; - } + /// // TODO: move to AVDecoder //if (hurry_up) { // codec_ctx->skip_frame = AVDISCARD_NONREF; @@ -499,6 +494,14 @@ bool AVDemuxer::openCodecs() //} bool skipframes = false; v_codec_context->skip_frame = skipframes ? AVDISCARD_NONREF : AVDISCARD_DEFAULT; + if (vCodec->capabilities & CODEC_CAP_DR1) + v_codec_context->flags |= CODEC_FLAG_EMU_EDGE; + //avcodec_open(v_codec_context, vCodec) //deprecated + ret = avcodec_open2(v_codec_context, vCodec, NULL); + if (ret < 0) { + qWarning("open video codec failed: %s", av_err2str(ret)); + _has_vedio = false; + } } started_ = false; return _has_audio || _has_vedio; @@ -534,7 +537,7 @@ bool AVDemuxer::autoResetStream() const { return auto_reset_stream; } - +//TODO: code like setStream, simplify bool AVDemuxer::setStreamIndex(StreamType st, int index) { QList *streams = 0; diff --git a/src/QtAV/AVDecoder.h b/src/QtAV/AVDecoder.h index 5397a3850..1378cf7fe 100644 --- a/src/QtAV/AVDecoder.h +++ b/src/QtAV/AVDecoder.h @@ -37,13 +37,23 @@ class Q_EXPORT AVDecoder public: AVDecoder(); virtual ~AVDecoder(); + /* + * default is open FFmpeg codec context + * codec config must be done before open + */ + virtual bool open(); + virtual bool close(); void flush(); void setCodecContext(AVCodecContext* codecCtx); //protected AVCodecContext* codecContext() const; + // force a codec + void setCodecName(const QString& name); + QString codecName() const; + //? low resolution decoding, 0: normal, 1-> 1/2 size, 2->1/4 size void setLowResolution(int lowres); int lowResolution() const; - // 0: auto detect by av_cpu_count() + // -1: auto detect by QThread::idealThreadCount(). 0: set by ffmpeg(default) void setDecodeThreads(int threads); int decodeThreads() const; void setThreadSlice(bool s); diff --git a/src/QtAV/AVDemuxer.h b/src/QtAV/AVDemuxer.h index 4dd266b33..bb5d51fc6 100644 --- a/src/QtAV/AVDemuxer.h +++ b/src/QtAV/AVDemuxer.h @@ -73,8 +73,8 @@ class Q_EXPORT AVDemuxer : public QObject //QIODevice? bool close(); bool loadFile(const QString& fileName); bool isLoaded(const QString& fileName) const; - bool openCodecs(); - bool closeCodecs(); + Q_DECL_DEPRECATED bool openCodecs(); + Q_DECL_DEPRECATED bool closeCodecs(); void putFlushPacket(); bool readFrame(); @@ -83,6 +83,8 @@ class Q_EXPORT AVDemuxer : public QObject //QIODevice? void setClock(AVClock *c); AVClock *clock() const; + + bool isSeekable() const; void setSeekUnit(SeekUnit unit); SeekUnit seekUnit() const; void setSeekTarget(SeekTarget target); diff --git a/src/QtAV/private/AVDecoder_p.h b/src/QtAV/private/AVDecoder_p.h index 678303cf6..c21856f3c 100644 --- a/src/QtAV/private/AVDecoder_p.h +++ b/src/QtAV/private/AVDecoder_p.h @@ -35,13 +35,14 @@ class Q_EXPORT AVDecoderPrivate : public DPtrPrivate AVDecoderPrivate(): codec_ctx(0) , available(true) + , fast(false) , frame(0) , got_frame_ptr(0) , thread_slice(1) , low_resolution(0) { frame = avcodec_alloc_frame(); - threads = qMax(1, QThread::idealThreadCount()); //av_cpu_count is not available for old ffmpeg. c++11 thread::hardware_concurrency() + threads = qMax(0, QThread::idealThreadCount()); //av_cpu_count is not available for old ffmpeg. c++11 thread::hardware_concurrency() } virtual ~AVDecoderPrivate() { if (frame) { @@ -52,6 +53,7 @@ class Q_EXPORT AVDecoderPrivate : public DPtrPrivate AVCodecContext *codec_ctx; //set once and not change bool available; + bool fast; AVFrame *frame; //set once and not change QByteArray decoded; int got_frame_ptr; @@ -59,6 +61,7 @@ class Q_EXPORT AVDecoderPrivate : public DPtrPrivate int threads; bool thread_slice; int low_resolution; + QString name; }; } //namespace QtAV