From f32edcb5492ce1920361f0ac62516efe11e0c989 Mon Sep 17 00:00:00 2001 From: barracuda156 Date: Sat, 23 Dec 2023 20:57:17 +0800 Subject: [PATCH] FFMpeg: fix compatibility with modern FFMpeg Backport of: https://github.com/zaps166/QMPlay2/commit/6da1224fe664ecc2c8d8c8e0b57a81605938c35a https://github.com/zaps166/QMPlay2/commit/66a8c123c54bd83bcdc2a6ab9b073acd0a97368e https://github.com/zaps166/QMPlay2/commit/f9dbff5e3e3eab7f877d28a25dcbbc4839c88213 diff --git README.md README.md index 31571b5e..6a3e82e7 100644 --- README.md +++ README.md @@ -157,7 +157,7 @@ For CMake build be sure that you have correct CMake version: - QtOpenGL - not used since Qt 5.6.0, - QtDBus - Linux/BSD only, - QtSvg - for SVG icons, -- FFmpeg >= 2.2 (>= 2.5.x recommended; >= 3.1.x recommended for CUVID): +- FFmpeg >= 3.1: - libavformat - requires OpenSSL or GnuTLS for https support, - libavcodec - for FFmpeg module only, - libswscale, diff --git src/modules/CUVID/CuvidDec.cpp src/modules/CUVID/CuvidDec.cpp index 637878c1..de44793e 100644 --- src/modules/CUVID/CuvidDec.cpp +++ src/modules/CUVID/CuvidDec.cpp @@ -44,28 +44,6 @@ extern "C" #include } -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101) - #define NEW_BSF_API -#else - #warning "FFmpeg 3.1 or higher is required for H264 and HEVC non Annex B support in CUVID" - - static bool checkAnnexB(const QByteArray &extraData, AVCodecID codecID) - { - const quint8 *data = (const quint8 *)extraData.constData(); - const int size = extraData.size(); - switch (codecID) - { - case AV_CODEC_ID_H264: - return size == 0 || (size >= 3 && (!data[0] && !data[1] && (data[2] == 1 || (size >= 4 && data[3] == 1)))); - case AV_CODEC_ID_HEVC: - return size < 23 || (!data[0] && !data[1] && (data[2] == 1 || data[3] == 1)); - default: - break; - } - return false; - } -#endif - namespace cu { using cuInitType = CUresult CUDAAPI (*)(unsigned int flags); @@ -520,14 +498,10 @@ CuvidDec::~CuvidDec() if (!m_writer) cu::ctxDestroy(m_cuCtx); } -#ifdef NEW_BSF_API av_bsf_free(&m_bsfCtx); -#endif if (m_swsCtx) sws_freeContext(m_swsCtx); -#ifdef NEW_BSF_API av_packet_free(&m_pkt); -#endif av_buffer_unref(&m_nv12Chroma); for (int p = 0; p < 3; ++p) av_buffer_unref(&m_frameBuffer[p]); @@ -675,7 +649,6 @@ int CuvidDec::decodeVideo(Packet &encodedPacket, VideoFrame &decoded, QByteArray { cuvidPkt.flags = CUVID_PKT_TIMESTAMP; cuvidPkt.timestamp = encodedPacket.ts.pts() * 10000000.0 + 0.5; -#ifdef NEW_BSF_API if (m_bsfCtx) { m_pkt->buf = encodedPacket.toAvBufferRef(); @@ -698,7 +671,6 @@ int CuvidDec::decodeVideo(Packet &encodedPacket, VideoFrame &decoded, QByteArray cuvidPkt.payload_size = m_pkt->size; } else -#endif { cuvidPkt.payload = encodedPacket.constData(); cuvidPkt.payload_size = encodedPacket.size(); @@ -710,10 +682,8 @@ int CuvidDec::decodeVideo(Packet &encodedPacket, VideoFrame &decoded, QByteArray if (cuvidPkt.flags == CUVID_PKT_TIMESTAMP && videoDataParsed) m_timestamps.enqueue(encodedPacket.ts); -#ifdef NEW_BSF_API if (m_pkt) av_packet_unref(m_pkt); -#endif if (m_cuvidSurfaces.isEmpty()) encodedPacket.ts.setInvalid(); @@ -853,11 +823,7 @@ bool CuvidDec::open(StreamInfo &streamInfo, VideoWriter *writer) int depth = 8; if (const AVPixFmtDescriptor *pixDesc = av_pix_fmt_desc_get(pixFmt)) { -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 102) depth = pixDesc->comp[0].depth; -#else - depth = pixDesc->comp[0].depth_minus1 + 1; -#endif } cudaVideoCodec codec; @@ -906,7 +872,6 @@ bool CuvidDec::open(StreamInfo &streamInfo, VideoWriter *writer) const AVBitStreamFilter *bsf = nullptr; switch (codec) { -#ifdef NEW_BSF_API case cudaVideoCodec_H264: bsf = av_bsf_get_by_name("h264_mp4toannexb"); if (!bsf) @@ -917,14 +882,6 @@ bool CuvidDec::open(StreamInfo &streamInfo, VideoWriter *writer) if (!bsf) return false; break; -#else - case cudaVideoCodec_H264: - case cudaVideoCodec_HEVC: - if (checkAnnexB(streamInfo.data, avCodec->id)) - break; - QMPlay2Core.logError("CUVID :: " + tr("Compilation with FFmpeg 3.1 or higher is required for H264 and HEVC support!"), true, true); - return false; -#endif default: break; } @@ -933,7 +890,6 @@ bool CuvidDec::open(StreamInfo &streamInfo, VideoWriter *writer) if (!bsf) extraData = streamInfo.data; -#ifdef NEW_BSF_API else { av_bsf_alloc(bsf, &m_bsfCtx); @@ -951,7 +907,6 @@ bool CuvidDec::open(StreamInfo &streamInfo, VideoWriter *writer) m_pkt = av_packet_alloc(); } -#endif m_width = streamInfo.W; m_height = streamInfo.H; diff --git src/modules/FFmpeg/FFCommon.cpp src/modules/FFmpeg/FFCommon.cpp index f2521500..c2df0e5f 100644 --- src/modules/FFmpeg/FFCommon.cpp +++ src/modules/FFmpeg/FFCommon.cpp @@ -31,32 +31,9 @@ extern "C" #endif } -AVPacket *FFCommon::createAVPacket() -{ - AVPacket *packet; -#if LIBAVCODEC_VERSION_MAJOR >= 57 - packet = av_packet_alloc(); -#else - packet = (AVPacket *)av_malloc(sizeof(AVPacket)); - av_init_packet(packet); -#endif - return packet; -} -void FFCommon::freeAVPacket(AVPacket *&packet) -{ -#if LIBAVCODEC_VERSION_MAJOR >= 57 - av_packet_free(&packet); -#else - if (packet) - av_packet_unref(packet); - av_freep(&packet); -#endif -} - #ifdef QMPlay2_VDPAU AVVDPAUContext *FFCommon::allocAVVDPAUContext(AVCodecContext *codecCtx) { -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 13, 100) // FFmpeg 2.5.0 // Since FFmpeg 3.3 we must not use "av_vdpau_alloc_context()" or "AVVDPAUContext" structure size // for allocating "AVCodecContext::hwaccel_context", because internally it always uses field from // different internal structure which is larger. Using different struct inside FFmpeg was provided @@ -67,8 +44,5 @@ AVVDPAUContext *FFCommon::allocAVVDPAUContext(AVCodecContext *codecCtx) if (av_vdpau_bind_context(codecCtx, 0, nullptr, 0) == 0) return (AVVDPAUContext *)codecCtx->hwaccel_context; return nullptr; -#else - return av_vdpau_alloc_context(); -#endif } #endif diff --git src/modules/FFmpeg/FFCommon.hpp src/modules/FFmpeg/FFCommon.hpp index 9aebf57c..3e82c686 100644 --- src/modules/FFmpeg/FFCommon.hpp +++ src/modules/FFmpeg/FFCommon.hpp @@ -41,9 +41,6 @@ class VideoFrame; namespace FFCommon { - AVPacket *createAVPacket(); - void freeAVPacket(AVPacket *&packet); - #ifdef QMPlay2_VDPAU AVVDPAUContext *allocAVVDPAUContext(AVCodecContext *codecCtx); #endif diff --git src/modules/FFmpeg/FFDec.cpp src/modules/FFmpeg/FFDec.cpp index fd46bb37..13df6be1 100644 --- src/modules/FFmpeg/FFDec.cpp +++ src/modules/FFmpeg/FFDec.cpp @@ -39,7 +39,7 @@ FFDec::FFDec(QMutex &avcodec_mutex) : FFDec::~FFDec() { av_frame_free(&frame); - FFCommon::freeAVPacket(packet); + av_packet_free(&packet); if (codecIsOpen) { avcodec_mutex.lock(); @@ -84,7 +84,7 @@ bool FFDec::openCodec(AVCodec *codec) return false; } avcodec_mutex.unlock(); - packet = FFCommon::createAVPacket(); + packet = av_packet_alloc(); switch (codec_ctx->codec_type) { case AVMEDIA_TYPE_VIDEO: diff --git src/modules/FFmpeg/FFDecSW.cpp src/modules/FFmpeg/FFDecSW.cpp index 97930c46..dfae9f78 100644 --- src/modules/FFmpeg/FFDecSW.cpp +++ src/modules/FFmpeg/FFDecSW.cpp @@ -31,6 +31,10 @@ extern "C" #include } +#ifndef AV_CODEC_FLAG2_FAST + #define AV_CODEC_FLAG2_FAST CODEC_FLAG2_FAST +#endif + FFDecSW::FFDecSW(QMutex &avcodec_mutex, Module &module) : FFDec(avcodec_mutex), threads(0), lowres(0), @@ -213,14 +217,14 @@ int FFDecSW::decodeVideo(Packet &encodedPacket, VideoFrame &decoded, QByteArray codec_ctx->skip_loop_filter = AVDISCARD_ALL; if (hurry_up > 1) codec_ctx->skip_idct = AVDISCARD_NONREF; - codec_ctx->flags2 |= CODEC_FLAG2_FAST; + codec_ctx->flags2 |= AV_CODEC_FLAG2_FAST; } else { if (!forceSkipFrames) codec_ctx->skip_frame = AVDISCARD_DEFAULT; codec_ctx->skip_loop_filter = codec_ctx->skip_idct = AVDISCARD_DEFAULT; - codec_ctx->flags2 &= ~CODEC_FLAG2_FAST; + codec_ctx->flags2 &= ~AV_CODEC_FLAG2_FAST; } bytes_consumed = avcodec_decode_video2(codec_ctx, frame, &frameFinished, packet); @@ -304,15 +308,9 @@ bool FFDecSW::decodeSubtitle(const Packet &encodedPacket, double pos, QMPlay2OSD buff->y = av_clip(rect->y, 0, h - buff->h); buff->bitmap.resize((buff->w * buff->h) << 2); -#if LIBAVCODEC_VERSION_MAJOR >= 57 const uint8_t *source = (uint8_t *)rect->data[0]; const uint32_t *palette = (uint32_t *)rect->data[1]; const int linesize = rect->linesize[0]; -#else - const uint8_t *source = (uint8_t *)rect->pict.data[0]; - const uint32_t *palette = (uint32_t *)rect->pict.data[1]; - const int linesize = rect->pict.linesize[0]; -#endif uint32_t *dest = (uint32_t *)buff->bitmap.data(); for (int y = 0; y < buff->h; ++y) @@ -339,8 +337,6 @@ bool FFDecSW::open(StreamInfo &streamInfo, VideoWriter *) return false; if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { - if (codec->capabilities & CODEC_CAP_DR1) - codec_ctx->flags |= CODEC_FLAG_EMU_EDGE; //Does nothing since FFmpeg 2.3 if ((codec_ctx->thread_count = threads) != 1) { if (!thread_type_slice) diff --git src/modules/FFmpeg/FFDecVDPAU.cpp src/modules/FFmpeg/FFDecVDPAU.cpp index 8624a3e7..44050402 100644 --- src/modules/FFmpeg/FFDecVDPAU.cpp +++ src/modules/FFmpeg/FFDecVDPAU.cpp @@ -75,7 +75,7 @@ bool FFDecVDPAU::open(StreamInfo &streamInfo, VideoWriter *writer) new HWAccelHelper(codec_ctx, AV_PIX_FMT_VDPAU, vdpauCtx, vdpauWriter->getSurfacesQueue()); - if (pix_fmt == AV_PIX_FMT_YUVJ420P && avcodec_version() >= 0x383C64) + if (pix_fmt == AV_PIX_FMT_YUVJ420P) codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; //Force full color range if (openCodec(codec)) diff --git src/modules/FFmpeg/FFReader.cpp src/modules/FFmpeg/FFReader.cpp index 6bdb00d0..4e3b7d54 100644 --- src/modules/FFmpeg/FFReader.cpp +++ src/modules/FFmpeg/FFReader.cpp @@ -105,11 +105,7 @@ void FFReader::pause() } bool FFReader::atEnd() const { -#if LIBAVFORMAT_VERSION_MAJOR >= 56 return avio_feof(avioCtx); -#else - return url_feof(avioCtx); -#endif } void FFReader::abort() { diff --git src/modules/FFmpeg/FFmpeg.cpp src/modules/FFmpeg/FFmpeg.cpp index ca5fb817..b6285a61 100644 --- src/modules/FFmpeg/FFmpeg.cpp +++ src/modules/FFmpeg/FFmpeg.cpp @@ -258,9 +258,7 @@ ModuleSettingsWidget::ModuleSettingsWidget(Module &module) : reconnectStreamedB = new QCheckBox(tr("Try to automatically reconnect live streams on error")); reconnectStreamedB->setChecked(sets().getBool("ReconnectStreamed")); -#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(57, 25, 100) - reconnectStreamedB->setEnabled(false); -#endif + reconnectStreamedB->setEnabled(false); decoderB = new QGroupBox(tr("Software decoder")); decoderB->setCheckable(true); diff --git src/modules/FFmpeg/FormatContext.cpp src/modules/FFmpeg/FormatContext.cpp index e989db44..da13fa3d 100644 --- src/modules/FFmpeg/FormatContext.cpp +++ src/modules/FFmpeg/FormatContext.cpp @@ -25,23 +25,13 @@ #include #include -#if LIBAVFORMAT_VERSION_INT >= 0x373000 // >= 55.48.00 - #define HAS_REPLAY_GAIN -#endif - extern "C" { #include -#ifdef HAS_REPLAY_GAIN #include -#endif #include -#if LIBAVFORMAT_VERSION_MAJOR <= 55 - #include -#endif } -#if LIBAVFORMAT_VERSION_MAJOR > 55 static void matroska_fix_ass_packet(AVRational stream_timebase, AVPacket *pkt) { AVBufferRef *line; @@ -70,7 +60,7 @@ static void matroska_fix_ass_packet(AVRational stream_timebase, AVPacket *pkt) es = ec / 100; ec -= 100 * es; *ptr++ = '\0'; - len = 50 + end - ptr + FF_INPUT_BUFFER_PADDING_SIZE; + len = 50 + end - ptr + AV_INPUT_BUFFER_PADDING_SIZE; if (!(line = av_buffer_alloc(len))) return; snprintf((char *)line->data, len, "Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n", layer, sh, sm, ss, sc, eh, em, es, ec, ptr); @@ -80,35 +70,6 @@ static void matroska_fix_ass_packet(AVRational stream_timebase, AVPacket *pkt) pkt->size = strlen((char *)line->data); } } -#endif - -#if LIBAVFORMAT_VERSION_INT >= 0x392900 - static inline AVCodecParameters *codecParams(AVStream *stream) - { - return stream->codecpar; - } - static inline const char *getPixelFormat(AVStream *stream) - { - return av_get_pix_fmt_name((AVPixelFormat)stream->codecpar->format); - } - static inline const char *getSampleFormat(AVStream *stream) - { - return av_get_sample_fmt_name((AVSampleFormat)stream->codecpar->format); - } -#else - static inline AVCodecContext *codecParams(AVStream *stream) - { - return stream->codec; - } - static inline const char *getPixelFormat(AVStream *stream) - { - return av_get_pix_fmt_name(stream->codec->pix_fmt); - } - static inline const char *getSampleFormat(AVStream *stream) - { - return av_get_sample_fmt_name(stream->codec->sample_fmt); - } -#endif static QByteArray getTag(AVDictionary *metadata, const char *key, const bool deduplicate = true) { @@ -159,14 +120,14 @@ static QByteArray getTag(AVDictionary *metadata, const char *key, const bool ded static void fixFontsAttachment(AVStream *stream) { - if (codecParams(stream)->codec_type == AVMEDIA_TYPE_ATTACHMENT && codecParams(stream)->codec_id == AV_CODEC_ID_NONE) + if (stream->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT && stream->codecpar->codec_id == AV_CODEC_ID_NONE) { // If codec for fonts is unknown - check the attachment file name extension const QString attachmentFileName = getTag(stream->metadata, "filename", false); if (attachmentFileName.endsWith(".otf", Qt::CaseInsensitive)) - codecParams(stream)->codec_id = AV_CODEC_ID_OTF; + stream->codecpar->codec_id = AV_CODEC_ID_OTF; else if (attachmentFileName.endsWith(".ttf", Qt::CaseInsensitive)) - codecParams(stream)->codec_id = AV_CODEC_ID_TTF; + stream->codecpar->codec_id = AV_CODEC_ID_TTF; } } @@ -175,8 +136,8 @@ static bool streamNotValid(AVStream *stream) return ( (stream->disposition & AV_DISPOSITION_ATTACHED_PIC) || - (codecParams(stream)->codec_type == AVMEDIA_TYPE_DATA) || - (codecParams(stream)->codec_type == AVMEDIA_TYPE_ATTACHMENT && codecParams(stream)->codec_id != AV_CODEC_ID_TTF && codecParams(stream)->codec_id != AV_CODEC_ID_OTF) + (stream->codecpar->codec_type == AVMEDIA_TYPE_DATA) || + (stream->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT && stream->codecpar->codec_id != AV_CODEC_ID_TTF && stream->codecpar->codec_id != AV_CODEC_ID_OTF) ); } @@ -254,28 +215,26 @@ FormatContext::~FormatContext() { for (AVStream *stream : streams) { - if (codecParams(stream) && !streamNotValid(stream)) + if (stream->codecpar && !streamNotValid(stream)) { - //Data is allocated in QByteArray, so FFmpeg mustn't free it! - codecParams(stream)->extradata = nullptr; - codecParams(stream)->extradata_size = 0; + // Data is allocated in QByteArray, so FFmpeg mustn't free it! + stream->codecpar->extradata = nullptr; + stream->codecpar->extradata_size = 0; } } avformat_close_input(&formatCtx); - FFCommon::freeAVPacket(packet); + av_packet_free(&packet); } delete oggHelper; } bool FormatContext::metadataChanged() const { -#if LIBAVFORMAT_VERSION_MAJOR > 55 if (formatCtx->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) { formatCtx->event_flags = 0; isMetadataChanged = true; } -#endif if (isMetadataChanged) { isMetadataChanged = false; @@ -306,7 +265,7 @@ QList FormatContext::getPrograms() const const int idx = index_map[ff_idx]; if (idx > -1) { - const QMPlay2MediaType type = (QMPlay2MediaType)codecParams(streams[ff_idx])->codec_type; + const QMPlay2MediaType type = (QMPlay2MediaType)streams[ff_idx]->codecpar->codec_type; if (type != QMPLAY2_TYPE_UNKNOWN) programInfo.streams += {idx, type}; } @@ -399,7 +358,6 @@ QList FormatContext::tags() const } bool FormatContext::getReplayGain(bool album, float &gain_db, float &peak) const { -#ifdef HAS_REPLAY_GAIN const int streamIdx = av_find_best_stream(formatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0); if (streamIdx > -1) { @@ -434,7 +392,6 @@ bool FormatContext::getReplayGain(bool album, float &gain_db, float &peak) const return true; } } -#endif if (AVDictionary *dict = getMetadata()) { QString album_gain_db = getTag(dict, "REPLAYGAIN_ALBUM_GAIN", false); @@ -514,37 +471,28 @@ bool FormatContext::seek(double pos, bool backward) pos = 0.0; else if (len > 0.0 && pos > len) pos = len; -#ifndef MP3_FAST_SEEK - if (seekByByteOffset < 0) - { -#endif - const double posToSeek = pos + startTime; - const qint64 timestamp = ((streamsInfo.count() == 1) ? posToSeek : (backward ? floor(posToSeek) : ceil(posToSeek))) * AV_TIME_BASE; + const double posToSeek = pos + startTime; + const qint64 timestamp = ((streamsInfo.count() == 1) ? posToSeek : (backward ? floor(posToSeek) : ceil(posToSeek))) * AV_TIME_BASE; - isOk = av_seek_frame(formatCtx, -1, timestamp, backward ? AVSEEK_FLAG_BACKWARD : 0) >= 0; - if (!isOk) + isOk = av_seek_frame(formatCtx, -1, timestamp, backward ? AVSEEK_FLAG_BACKWARD : 0) >= 0; + if (!isOk) + { + const int ret = av_read_frame(formatCtx, packet); + if (ret == AVERROR_EOF || ret == 0) { - const int ret = av_read_frame(formatCtx, packet); - if (ret == AVERROR_EOF || ret == 0) - { - if (len <= 0.0 || pos < len) - isOk = av_seek_frame(formatCtx, -1, timestamp, !backward ? AVSEEK_FLAG_BACKWARD : 0) >= 0; //Negate "backward" and try again - else if (ret == AVERROR_EOF) - isOk = true; //Allow seek to the end of the file, clear buffers and finish the playback - if (isOk) - av_packet_unref(packet); - } - if (!isOk) //If seek failed - allow to use the packet - { - errFromSeek = ret; - maybeHasFrame = true; - } + if (len <= 0.0 || pos < len) + isOk = av_seek_frame(formatCtx, -1, timestamp, !backward ? AVSEEK_FLAG_BACKWARD : 0) >= 0; //Negate "backward" and try again + else if (ret == AVERROR_EOF) + isOk = true; // Allow seek to the end of the file, clear buffers and finish the playback + if (isOk) + av_packet_unref(packet); + } + if (!isOk) // If seek failed - allow to use the packet + { + errFromSeek = ret; + maybeHasFrame = true; } -#ifndef MP3_FAST_SEEK } - else if (length() > 0) - isOk = av_seek_frame(formatCtx, -1, (qint64)pos * (avio_size(formatCtx->pb) - seekByByteOffset) / length() + seekByByteOffset, AVSEEK_FLAG_BYTE | (backward ? AVSEEK_FLAG_BACKWARD : 0)) >= 0; -#endif if (isOk) { for (int i = 0; i < streamsTS.count(); ++i) @@ -609,49 +557,16 @@ bool FormatContext::read(Packet &encoded, int &idx) return true; } -#if LIBAVFORMAT_VERSION_MAJOR > 55 if (streams.at(ff_idx)->event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) { streams.at(ff_idx)->event_flags = 0; isMetadataChanged = true; } - if (fixMkvAss && codecParams(streams.at(ff_idx))->codec_id == AV_CODEC_ID_ASS) + if (fixMkvAss && streams.at(ff_idx)->codecpar->codec_id == AV_CODEC_ID_ASS) matroska_fix_ass_packet(streams.at(ff_idx)->time_base, packet); -#else - if (isStreamed) - { - char *value = nullptr; - av_opt_get(formatCtx, "icy_metadata_packet", AV_OPT_SEARCH_CHILDREN, (quint8 **)&value); - QString icyPacket = value; - av_free(value); - int idx = icyPacket.indexOf("StreamTitle='"); - if (idx > -1) - { - int idx2 = icyPacket.indexOf("';", idx += 13); - if (idx2 > -1) - { - AVDictionaryEntry *e = av_dict_get(formatCtx->metadata, "StreamTitle", nullptr, AV_DICT_IGNORE_SUFFIX); - icyPacket = icyPacket.mid(idx, idx2-idx); - if (!e || QString(e->value) != icyPacket) - { - av_dict_set(&formatCtx->metadata, "StreamTitle", icyPacket.toUtf8(), 0); - isMetadataChanged = true; - } - } - } - else if (AVDictionary *dict = getMetadata()) - { - if (metadata != dict) - { - metadata = dict; - isMetadataChanged = true; - } - } - } -#endif - if (!packet->buf || forceCopy) //Buffer isn't reference-counted, so copy the data - encoded.assign(packet->data, packet->size, packet->size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!packet->buf || forceCopy) // Buffer isn't reference-counted, so copy the data + encoded.assign(packet->data, packet->size, packet->size + AV_INPUT_BUFFER_PADDING_SIZE); else { encoded.assign(packet->buf, packet->size); @@ -660,22 +575,11 @@ bool FormatContext::read(Packet &encoded, int &idx) const double time_base = av_q2d(streams.at(ff_idx)->time_base); -#ifndef MP3_FAST_SEEK - if (seekByByteOffset < 0) -#endif - { - encoded.ts.setInvalid(); - if (packet->dts != QMPLAY2_NOPTS_VALUE) - encoded.ts.setDts(packet->dts * time_base, startTime); - if (packet->pts != QMPLAY2_NOPTS_VALUE) - encoded.ts.setPts(packet->pts * time_base, startTime); - } -#ifndef MP3_FAST_SEEK - else if (packet->pos > -1 && length() > 0.0) - lastTime = encoded.ts = ((packet->pos - seekByByteOffset) * length()) / (avio_size(formatCtx->pb) - seekByByteOffset); - else - encoded.ts = lastTime; -#endif + encoded.ts.setInvalid(); + if (packet->dts != QMPLAY2_NOPTS_VALUE) + encoded.ts.setDts(packet->dts * time_base, startTime); + if (packet->pts != QMPLAY2_NOPTS_VALUE) + encoded.ts.setPts(packet->pts * time_base, startTime); if (packet->duration > 0) encoded.duration = packet->duration * time_base; @@ -765,10 +669,8 @@ bool FormatContext::open(const QString &_url, const QString ¶m) if (!inputFmt) { url = Functions::prepareFFmpegUrl(_url, options); -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 25, 100) if (!isLocal && reconnectStreamed) av_dict_set(&options, "reconnect_streamed", "1", 0); -#endif } formatCtx = avformat_alloc_context(); @@ -800,12 +702,8 @@ bool FormatContext::open(const QString &_url, const QString ¶m) stillImage = true; } -#ifdef MP3_FAST_SEEK if (name() == "mp3") - formatCtx->flags |= AVFMT_FLAG_FAST_SEEK; //This should be set before "avformat_open_input", but seems to be working for MP3... -#else - seekByByteOffset = formatCtx->pb ? avio_tell(formatCtx->pb) : -1; //formatCtx->data_offset, moved to private since FFmpeg 2.6 -#endif + formatCtx->flags |= AVFMT_FLAG_FAST_SEEK; // This should be set before "avformat_open_input", but seems to be working for MP3... avcodec_mutex.lock(); if (avformat_find_stream_info(formatCtx, nullptr) < 0) @@ -815,14 +713,10 @@ bool FormatContext::open(const QString &_url, const QString ¶m) } avcodec_mutex.unlock(); - isStreamed = !isLocal && formatCtx->duration <= 0; //QMPLAY2_NOPTS_VALUE is negative -#ifndef MP3_FAST_SEEK - if (seekByByteOffset > -1 && (isStreamed || name() != "mp3")) - seekByByteOffset = -1; -#endif + isStreamed = !isLocal && formatCtx->duration <= 0; // QMPLAY2_NOPTS_VALUE is negative #ifdef QMPlay2_libavdevice - forceCopy = name().contains("v4l2"); //Workaround for v4l2 - if many buffers are referenced demuxer doesn't produce proper timestamps (FFmpeg BUG?). + forceCopy = name().contains("v4l2"); // Workaround for v4l2 - if many buffers are referenced demuxer doesn't produce proper timestamps (FFmpeg BUG?). #else forceCopy = false; #endif @@ -845,11 +739,9 @@ bool FormatContext::open(const QString &_url, const QString ¶m) index_map[i] = streamsInfo.count(); streamsInfo += streamInfo; } -#if LIBAVFORMAT_VERSION_MAJOR > 55 - if (!fixMkvAss && codecParams(formatCtx->streams[i])->codec_id == AV_CODEC_ID_ASS && !strncasecmp(formatCtx->iformat->name, "matroska", 8)) + if (!fixMkvAss && formatCtx->streams[i]->codecpar->codec_id == AV_CODEC_ID_ASS && !strncasecmp(formatCtx->iformat->name, "matroska", 8)) fixMkvAss = true; formatCtx->streams[i]->event_flags = 0; -#endif streams += formatCtx->streams[i]; streamsTS[i] = 0.0; @@ -857,34 +749,14 @@ bool FormatContext::open(const QString &_url, const QString ¶m) if (streamsInfo.isEmpty()) return false; - isOneStreamOgg = (name() == "ogg" && streamsInfo.count() == 1); //Workaround for OGG network streams + isOneStreamOgg = (name() == "ogg" && streamsInfo.count() == 1); // Workaround for OGG network streams if (isStreamed && streamsInfo.count() == 1 && streamsInfo.at(0)->type == QMPLAY2_TYPE_SUBTITLE && formatCtx->pb && avio_size(formatCtx->pb) > 0) - isStreamed = false; //Allow subtitles streams to be non-streamed if size is known + isStreamed = false; // Allow subtitles streams to be non-streamed if size is known -#if LIBAVFORMAT_VERSION_MAJOR > 55 formatCtx->event_flags = 0; -#else - if (!isStreamed) - metadata = nullptr; - else - { - char *value = nullptr; - av_opt_get(formatCtx, "icy_metadata_headers", AV_OPT_SEARCH_CHILDREN, (quint8 **)&value); - QStringList icyHeaders = QString(value).split("\n", QString::SkipEmptyParts); - av_free(value); - for (const QString &icy : icyHeaders) - { - if (icy.startsWith("icy-name: ")) - av_dict_set(&formatCtx->metadata, "icy-name", icy.mid(10).toUtf8(), 0); - else if (icy.startsWith("icy-description: ")) - av_dict_set(&formatCtx->metadata, "icy-description", icy.mid(17).toUtf8(), 0); - } - metadata = getMetadata(); - } -#endif - packet = FFCommon::createAVPacket(); + packet = av_packet_alloc(); return true; } @@ -910,11 +782,11 @@ StreamInfo *FormatContext::getStreamInfo(AVStream *stream) const StreamInfo *streamInfo = new StreamInfo; - if (const AVCodec *codec = avcodec_find_decoder(codecParams(stream)->codec_id)) + if (const AVCodec *codec = avcodec_find_decoder(stream->codecpar->codec_id)) streamInfo->codec_name = codec->name; streamInfo->must_decode = true; - if (const AVCodecDescriptor *codecDescr = avcodec_descriptor_get(codecParams(stream)->codec_id)) + if (const AVCodecDescriptor *codecDescr = avcodec_descriptor_get(stream->codecpar->codec_id)) { if (codecDescr->props & AV_CODEC_PROP_TEXT_SUB) streamInfo->must_decode = false; @@ -923,21 +795,21 @@ StreamInfo *FormatContext::getStreamInfo(AVStream *stream) const streamInfo->codec_name = codecDescr->name; } - streamInfo->bitrate = codecParams(stream)->bit_rate; - streamInfo->bpcs = codecParams(stream)->bits_per_coded_sample; - streamInfo->codec_tag = codecParams(stream)->codec_tag; + streamInfo->bitrate = stream->codecpar->bit_rate; + streamInfo->bpcs = stream->codecpar->bits_per_coded_sample; + streamInfo->codec_tag = stream->codecpar->codec_tag; streamInfo->is_default = stream->disposition & AV_DISPOSITION_DEFAULT; streamInfo->time_base.num = stream->time_base.num; streamInfo->time_base.den = stream->time_base.den; - streamInfo->type = (QMPlay2MediaType)codecParams(stream)->codec_type; //Enumy są takie same + streamInfo->type = (QMPlay2MediaType)stream->codecpar->codec_type; // Enumy są takie same - if (codecParams(stream)->extradata_size) + if (stream->codecpar->extradata_size) { - streamInfo->data.reserve(codecParams(stream)->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); - streamInfo->data.resize(codecParams(stream)->extradata_size); - memcpy(streamInfo->data.data(), codecParams(stream)->extradata, streamInfo->data.capacity()); - av_free(codecParams(stream)->extradata); - codecParams(stream)->extradata = (quint8 *)streamInfo->data.data(); + streamInfo->data.reserve(stream->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + streamInfo->data.resize(stream->codecpar->extradata_size); + memcpy(streamInfo->data.data(), stream->codecpar->extradata, streamInfo->data.capacity()); + av_free(stream->codecpar->extradata); + stream->codecpar->extradata = (quint8 *)streamInfo->data.data(); } if (streamInfo->type != QMPLAY2_TYPE_ATTACHMENT) @@ -963,25 +835,25 @@ StreamInfo *FormatContext::getStreamInfo(AVStream *stream) const switch (streamInfo->type) { case QMPLAY2_TYPE_AUDIO: - streamInfo->format = getSampleFormat(stream); - streamInfo->channels = codecParams(stream)->channels; - streamInfo->sample_rate = codecParams(stream)->sample_rate; - streamInfo->block_align = codecParams(stream)->block_align; + streamInfo->format = av_get_sample_fmt_name((AVSampleFormat)stream->codecpar->format); + streamInfo->channels = stream->codecpar->channels; + streamInfo->sample_rate = stream->codecpar->sample_rate; + streamInfo->block_align = stream->codecpar->block_align; break; case QMPLAY2_TYPE_VIDEO: - streamInfo->format = getPixelFormat(stream); + streamInfo->format = av_get_pix_fmt_name((AVPixelFormat)stream->codecpar->format); if (stream->sample_aspect_ratio.num) streamInfo->sample_aspect_ratio = av_q2d(stream->sample_aspect_ratio); - else if (codecParams(stream)->sample_aspect_ratio.num) - streamInfo->sample_aspect_ratio = av_q2d(codecParams(stream)->sample_aspect_ratio); - streamInfo->W = codecParams(stream)->width; - streamInfo->H = codecParams(stream)->height; + else if (stream->codecpar->sample_aspect_ratio.num) + streamInfo->sample_aspect_ratio = av_q2d(stream->codecpar->sample_aspect_ratio); + streamInfo->W = stream->codecpar->width; + streamInfo->H = stream->codecpar->height; if (!stillImage) streamInfo->FPS = av_q2d(stream->r_frame_rate); break; case AVMEDIA_TYPE_ATTACHMENT: streamInfo->title = getTag(stream->metadata, "filename", false); - switch (codecParams(stream)->codec_id) + switch (stream->codecpar->codec_id) { case AV_CODEC_ID_TTF: streamInfo->codec_name = "TTF"; diff --git src/modules/FFmpeg/FormatContext.hpp src/modules/FFmpeg/FormatContext.hpp index f2aaa9e3..6171f89c 100644 --- src/modules/FFmpeg/FormatContext.hpp +++ src/modules/FFmpeg/FormatContext.hpp @@ -30,10 +30,6 @@ extern "C" #include } -#if LIBAVFORMAT_VERSION_INT >= 0x382400 // >= 56.36.00 - #define MP3_FAST_SEEK -#endif - struct AVFormatContext; struct AVDictionary; struct AVStream; @@ -96,9 +92,6 @@ private: bool isPaused, fixMkvAss; mutable bool isMetadataChanged; double lastTime, startTime; -#ifndef MP3_FAST_SEEK - qint64 seekByByteOffset; -#endif bool isOneStreamOgg; bool forceCopy; @@ -108,9 +101,5 @@ private: bool artistWithTitle; bool stillImage; -#if LIBAVFORMAT_VERSION_MAJOR <= 55 - AVDictionary *metadata; -#endif - QMutex &avcodec_mutex; }; diff --git src/qmplay2/CMakeLists.txt src/qmplay2/CMakeLists.txt index d29382cd..01932ce6 100644 --- src/qmplay2/CMakeLists.txt +++ src/qmplay2/CMakeLists.txt @@ -143,10 +143,10 @@ set(QMPLAY2_RESOURCES languages.qrc ) -pkg_check_modules(LIBAVFORMAT libavformat>=55.33.100 REQUIRED) -pkg_check_modules(LIBAVCODEC libavcodec>=55.52.102 REQUIRED) -pkg_check_modules(LIBSWSCALE libswscale>=2.5.102 REQUIRED) -pkg_check_modules(LIBAVUTIL libavutil>=52.66.100 REQUIRED) +pkg_check_modules(LIBAVFORMAT libavformat>=57.40.101 REQUIRED) +pkg_check_modules(LIBAVCODEC libavcodec>=57.48.101 REQUIRED) +pkg_check_modules(LIBSWSCALE libswscale>=4.1.100 REQUIRED) +pkg_check_modules(LIBAVUTIL libavutil>=55.27.100 REQUIRED) if(USE_LIBASS) add_definitions(-DQMPLAY2_LIBASS) @@ -180,12 +180,12 @@ include_directories( if(USE_AVRESAMPLE) add_definitions(-DQMPLAY2_AVRESAMPLE) - pkg_check_modules(LIBAVRESAMPLE libavresample>=1.2.0 REQUIRED) + pkg_check_modules(LIBAVRESAMPLE libavresample>=4.0.0 REQUIRED) list(APPEND LIBQMPLAY2_LIBS ${LIBAVRESAMPLE_LIBRARIES}) include_directories(${LIBAVRESAMPLE_INCLUDE_DIRS}) link_directories(${LIBAVRESAMPLE_LIBRARY_DIRS}) else() - pkg_check_modules(LIBSWRESAMPLE libswresample>=0.18.100 REQUIRED) + pkg_check_modules(LIBSWRESAMPLE libswresample>=2.1.100 REQUIRED) list(APPEND LIBQMPLAY2_LIBS ${LIBSWRESAMPLE_LIBRARIES}) include_directories(${LIBSWRESAMPLE_INCLUDE_DIRS}) link_directories(${LIBSWRESAMPLE_LIBRARY_DIRS}) diff --git src/qmplay2/Functions.cpp src/qmplay2/Functions.cpp index baf5373e..35e59931 100644 --- src/qmplay2/Functions.cpp +++ src/qmplay2/Functions.cpp @@ -806,9 +806,7 @@ QString Functions::prepareFFmpegUrl(QString url, AVDictionary *&options, bool se if (!rawHeaders.isEmpty()) av_dict_set(&options, "headers", rawHeaders, 0); -#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(56, 36, 100) av_dict_set(&options, "reconnect", "1", 0); -#endif } return url; } diff --git src/qmplay2/MkvMuxer.cpp src/qmplay2/MkvMuxer.cpp index a011c56b..dda74c15 100644 --- src/qmplay2/MkvMuxer.cpp +++ src/qmplay2/MkvMuxer.cpp @@ -31,20 +31,7 @@ extern "C" #include -#if LIBAVFORMAT_VERSION_INT >= 0x392900 - static inline AVCodecParameters *codecParams(AVStream *stream) - { - return stream->codecpar; - } - #define HAS_CODECPAR -#else - static inline AVCodecContext *codecParams(AVStream *stream) - { - return stream->codec; - } -#endif - -/**/ +using namespace std; MkvMuxer::MkvMuxer(const QString &fileName, const QList &streamsInfo) { @@ -64,46 +51,32 @@ MkvMuxer::MkvMuxer(const QString &fileName, const QList &streamsIn stream->time_base.num = streamInfo->time_base.num; stream->time_base.den = streamInfo->time_base.den; -#ifndef HAS_CODECPAR - stream->codec->time_base = stream->time_base; - if (m_ctx->oformat->flags & AVFMT_GLOBALHEADER) - stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; -#endif - - codecParams(stream)->codec_type = (AVMediaType)streamInfo->type; - codecParams(stream)->codec_id = codec->id; + stream->codecpar->codec_type = (AVMediaType)streamInfo->type; + stream->codecpar->codec_id = codec->id; if (streamInfo->data.size() > 0) { - codecParams(stream)->extradata = (uint8_t *)av_mallocz(streamInfo->data.capacity()); - codecParams(stream)->extradata_size = streamInfo->data.size(); - memcpy(codecParams(stream)->extradata, streamInfo->data.constData(), codecParams(stream)->extradata_size); + stream->codecpar->extradata = (uint8_t *)av_mallocz(streamInfo->data.capacity()); + stream->codecpar->extradata_size = streamInfo->data.size(); + memcpy(stream->codecpar->extradata, streamInfo->data.constData(), stream->codecpar->extradata_size); } switch (streamInfo->type) { case QMPLAY2_TYPE_VIDEO: - codecParams(stream)->width = streamInfo->W; - codecParams(stream)->height = streamInfo->H; -#ifdef HAS_CODECPAR - codecParams(stream)->format = av_get_pix_fmt(streamInfo->format); -#else - codecParams(stream)->pix_fmt = av_get_pix_fmt(streamInfo->format); -#endif - codecParams(stream)->sample_aspect_ratio = av_d2q(streamInfo->sample_aspect_ratio, 10000); + stream->codecpar->width = streamInfo->W; + stream->codecpar->height = streamInfo->H; + stream->codecpar->format = av_get_pix_fmt(streamInfo->format); + stream->codecpar->sample_aspect_ratio = av_d2q(streamInfo->sample_aspect_ratio, 10000); stream->avg_frame_rate = av_d2q(streamInfo->FPS, 10000); if (streamInfo->is_default) stream->disposition |= AV_DISPOSITION_DEFAULT; break; case QMPLAY2_TYPE_AUDIO: - codecParams(stream)->channels = streamInfo->channels; - codecParams(stream)->sample_rate = streamInfo->sample_rate; - codecParams(stream)->block_align = streamInfo->block_align; -#ifdef HAS_CODECPAR - codecParams(stream)->format = av_get_sample_fmt(streamInfo->format); -#else - codecParams(stream)->sample_fmt = av_get_sample_fmt(streamInfo->format); -#endif + stream->codecpar->channels = streamInfo->channels; + stream->codecpar->sample_rate = streamInfo->sample_rate; + stream->codecpar->block_align = streamInfo->block_align; + stream->codecpar->format = av_get_sample_fmt(streamInfo->format); break; default: break; diff --git src/qmplay2/NetworkAccess.cpp src/qmplay2/NetworkAccess.cpp index 6cc81dd9..a5fd2e12 100644 --- src/qmplay2/NetworkAccess.cpp +++ src/qmplay2/NetworkAccess.cpp @@ -135,7 +135,6 @@ private: } switch (ret) { -#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(54, 15, 100) case AVERROR_HTTP_BAD_REQUEST: m_error = NetworkReply::Error::Connection400; break; @@ -154,7 +153,6 @@ private: case AVERROR_HTTP_SERVER_ERROR: m_error = NetworkReply::Error::Connection5XX; continue; // Continue if server error (e.g. Service Temporarily Unavailable) -#endif default: m_error = NetworkReply::Error::Connection; continue; // Continue if connection error