diff options
| author | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2020-01-31 22:46:41 +0000 |
|---|---|---|
| committer | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2020-01-31 22:46:41 +0000 |
| commit | ea4dd7e0d5b85a78af57af5484d3760c507898f0 (patch) | |
| tree | 736234a7827ab17bc4be7d9dfe98d0c72f6a65c2 | |
| parent | b28c35dba727aa637367e6b78c0afe5c4ae52c94 (diff) | |
| download | qmmp-ea4dd7e0d5b85a78af57af5484d3760c507898f0.tar.gz qmmp-ea4dd7e0d5b85a78af57af5484d3760c507898f0.tar.bz2 qmmp-ea4dd7e0d5b85a78af57af5484d3760c507898f0.zip | |
ffmpeg: refactoring
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@9220 90c681e8-e032-0410-971d-27865f9a5e38
| -rw-r--r-- | src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp | 365 | ||||
| -rw-r--r-- | src/plugins/Input/ffmpeg/decoder_ffmpeg.h | 31 |
2 files changed, 170 insertions, 226 deletions
diff --git a/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp b/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp index b1b1bb4f5..948993184 100644 --- a/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp +++ b/src/plugins/Input/ffmpeg/decoder_ffmpeg.cpp @@ -69,36 +69,19 @@ static int64_t ffmpeg_seek(void *data, int64_t offset, int whence) DecoderFFmpeg::DecoderFFmpeg(const QString &path, QIODevice *i) : Decoder(i) { - m_bitrate = 0; - m_totalTime = 0; - ic = nullptr; m_path = path; - m_temp_pkt.size = 0; - m_pkt.size = 0; - m_pkt.data = nullptr; - m_output_at = 0; - m_skipBytes = 0; - m_stream = nullptr; - m_decoded_frame = nullptr; - m_channels = 0; - c = nullptr; - audioIndex = 0; - m_seekTime = -1; - av_init_packet(&m_pkt); - av_init_packet(&m_temp_pkt); - m_input_buf = nullptr; + m_pkt = av_packet_alloc(); } DecoderFFmpeg::~DecoderFFmpeg() { m_bitrate = 0; - m_temp_pkt.size = 0; - if(c) - avcodec_free_context(&c); - if (ic) - avformat_free_context(ic); - if(m_pkt.data) - av_packet_unref(&m_pkt); + if(m_codecContext) + avcodec_free_context(&m_codecContext); + if (m_formatContext) + avformat_free_context(m_formatContext); + + av_packet_free(&m_pkt); if(m_stream) #if (LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 80, 100)) //ffmpeg-3.4 @@ -107,8 +90,8 @@ DecoderFFmpeg::~DecoderFFmpeg() av_free(m_stream); #endif - if(m_decoded_frame) - av_frame_free(&m_decoded_frame); + if(m_frame) + av_frame_free(&m_frame); } bool DecoderFFmpeg::initialize() @@ -116,8 +99,9 @@ bool DecoderFFmpeg::initialize() m_bitrate = 0; m_totalTime = 0; m_seekTime = -1; + m_eof = false; - ic = avformat_alloc_context(); + m_formatContext = avformat_alloc_context(); AVProbeData pd; memset(&pd, 0, sizeof(pd)); @@ -155,45 +139,45 @@ bool DecoderFFmpeg::initialize() } m_stream->seekable = !input()->isSequential(); m_stream->max_packet_size = INPUT_BUFFER_SIZE; - ic->pb = m_stream; + m_formatContext->pb = m_stream; - if(avformat_open_input(&ic, nullptr, fmt, nullptr) != 0) + if(avformat_open_input(&m_formatContext, nullptr, fmt, nullptr) != 0) { qDebug("DecoderFFmpeg: avformat_open_input() failed"); return false; } - avformat_find_stream_info(ic, nullptr); - if(ic->pb) - ic->pb->eof_reached = 0; + avformat_find_stream_info(m_formatContext, nullptr); + if(m_formatContext->pb) + m_formatContext->pb->eof_reached = 0; if (input()->isSequential()) { QMap<Qmmp::MetaData, QString> metaData; - AVDictionaryEntry *album = av_dict_get(ic->metadata,"album",nullptr,0); - AVDictionaryEntry *album_artist = av_dict_get(ic->metadata,"album_artist",nullptr,0); - AVDictionaryEntry *artist = av_dict_get(ic->metadata,"artist",nullptr,0); - AVDictionaryEntry *composer = av_dict_get(ic->metadata,"composer",nullptr,0); - AVDictionaryEntry *comment = av_dict_get(ic->metadata,"comment",nullptr,0); - AVDictionaryEntry *genre = av_dict_get(ic->metadata,"genre",nullptr,0); - AVDictionaryEntry *title = av_dict_get(ic->metadata,"title",nullptr,0); - AVDictionaryEntry *year = av_dict_get(ic->metadata,"date",nullptr,0); - AVDictionaryEntry *track = av_dict_get(ic->metadata,"track",nullptr,0); + AVDictionaryEntry *album = av_dict_get(m_formatContext->metadata,"album",nullptr,0); + AVDictionaryEntry *album_artist = av_dict_get(m_formatContext->metadata,"album_artist",nullptr,0); + AVDictionaryEntry *artist = av_dict_get(m_formatContext->metadata,"artist",nullptr,0); + AVDictionaryEntry *composer = av_dict_get(m_formatContext->metadata,"composer",nullptr,0); + AVDictionaryEntry *comment = av_dict_get(m_formatContext->metadata,"comment",nullptr,0); + AVDictionaryEntry *genre = av_dict_get(m_formatContext->metadata,"genre",nullptr,0); + AVDictionaryEntry *title = av_dict_get(m_formatContext->metadata,"title",nullptr,0); + AVDictionaryEntry *year = av_dict_get(m_formatContext->metadata,"date",nullptr,0); + AVDictionaryEntry *track = av_dict_get(m_formatContext->metadata,"track",nullptr,0); if(!album) - album = av_dict_get(ic->metadata,"WM/AlbumTitle",nullptr,0); + album = av_dict_get(m_formatContext->metadata,"WM/AlbumTitle",nullptr,0); if(!artist) - artist = av_dict_get(ic->metadata,"author",nullptr,0); + artist = av_dict_get(m_formatContext->metadata,"author",nullptr,0); if(!year) - year = av_dict_get(ic->metadata,"WM/Year",nullptr,0); + year = av_dict_get(m_formatContext->metadata,"WM/Year",nullptr,0); if(!year) - year = av_dict_get(ic->metadata,"year",nullptr,0); + year = av_dict_get(m_formatContext->metadata,"year",nullptr,0); if(!track) - track = av_dict_get(ic->metadata,"WM/Track",nullptr,0); + track = av_dict_get(m_formatContext->metadata,"WM/Track",nullptr,0); if(!track) - track = av_dict_get(ic->metadata,"WM/TrackNumber",nullptr,0); + track = av_dict_get(m_formatContext->metadata,"WM/TrackNumber",nullptr,0); if(album) metaData.insert(Qmmp::ALBUM, QString::fromUtf8(album->value).trimmed()); @@ -217,35 +201,35 @@ bool DecoderFFmpeg::initialize() } //replay gain - ReplayGainReader rg(ic); + ReplayGainReader rg(m_formatContext); setReplayGainInfo(rg.replayGainInfo()); - c = avcodec_alloc_context3(nullptr); - ic->flags |= AVFMT_FLAG_GENPTS; - av_read_play(ic); - audioIndex = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0); - if(audioIndex < 0) + m_codecContext = avcodec_alloc_context3(nullptr); + m_formatContext->flags |= AVFMT_FLAG_GENPTS; + av_read_play(m_formatContext); + m_audioIndex = av_find_best_stream(m_formatContext, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0); + if(m_audioIndex < 0) { qWarning("DecoderFFmpeg: unable to find audio stream"); return false; } - avcodec_parameters_to_context(c, ic->streams[audioIndex]->codecpar); + avcodec_parameters_to_context(m_codecContext, m_formatContext->streams[m_audioIndex]->codecpar); - if (c->channels == 1) + if (m_codecContext->channels == 1) { - c->request_channel_layout = AV_CH_LAYOUT_MONO; - m_channels = c->channels; + m_codecContext->request_channel_layout = AV_CH_LAYOUT_MONO; + m_channels = m_codecContext->channels; } else { - c->request_channel_layout = AV_CH_LAYOUT_STEREO; + m_codecContext->request_channel_layout = AV_CH_LAYOUT_STEREO; m_channels = 2; } - av_dump_format(ic,0,nullptr,0); + av_dump_format(m_formatContext,0,nullptr,0); - AVCodec *codec = avcodec_find_decoder(c->codec_id); + AVCodec *codec = avcodec_find_decoder(m_codecContext->codec_id); if (!codec) { @@ -253,21 +237,21 @@ bool DecoderFFmpeg::initialize() return false; } - if (avcodec_open2(c, codec, nullptr) < 0) + if (avcodec_open2(m_codecContext, codec, nullptr) < 0) { qWarning("DecoderFFmpeg: error while opening codec for output stream"); return false; } - m_decoded_frame = av_frame_alloc(); - m_totalTime = input()->isSequential() ? 0 : ic->duration * 1000 / AV_TIME_BASE; + m_frame = av_frame_alloc(); + m_totalTime = input()->isSequential() ? 0 : m_formatContext->duration * 1000 / AV_TIME_BASE; - if(c->codec_id == AV_CODEC_ID_SHORTEN) //ffmpeg bug workaround + if(m_codecContext->codec_id == AV_CODEC_ID_SHORTEN) //ffmpeg bug workaround m_totalTime = 0; Qmmp::AudioFormat format = Qmmp::PCM_UNKNOWN; - switch(c->sample_fmt) + switch(m_codecContext->sample_fmt) { case AV_SAMPLE_FMT_U8: case AV_SAMPLE_FMT_U8P: @@ -290,13 +274,13 @@ bool DecoderFFmpeg::initialize() return false; } - setProperty(Qmmp::FORMAT_NAME, QString::fromLatin1(c->codec->name)); - configure(c->sample_rate, m_channels, format); + setProperty(Qmmp::FORMAT_NAME, QString::fromLatin1(m_codecContext->codec->name)); + configure(m_codecContext->sample_rate, m_channels, format); - if(ic->bit_rate) - m_bitrate = ic->bit_rate/1000; - if(c->bit_rate) - m_bitrate = c->bit_rate/1000; + if(m_formatContext->bit_rate) + m_bitrate = m_formatContext->bit_rate/1000; + if(m_codecContext->bit_rate) + m_bitrate = m_codecContext->bit_rate/1000; qDebug("DecoderFFmpeg: initialize succes"); qDebug() << "DecoderFFmpeg: total time =" << m_totalTime; @@ -317,199 +301,160 @@ qint64 DecoderFFmpeg::read(unsigned char *audio, qint64 maxSize) { m_skipBytes = 0; - if(!m_output_at) + if(!m_output_size) fillBuffer(); - if(!m_output_at) + if(!m_output_size) return 0; - qint64 len = qMin(m_output_at, maxSize); + qint64 len = qMin(m_output_size, maxSize); - if(av_sample_fmt_is_planar(c->sample_fmt) && m_channels > 1) + if(av_sample_fmt_is_planar(m_codecContext->sample_fmt) && m_channels > 1) { - int bps = av_get_bytes_per_sample(c->sample_fmt); + int bps = av_get_bytes_per_sample(m_codecContext->sample_fmt); for(int i = 0; i < len / bps; i++) { - memcpy(audio + i * bps, m_decoded_frame->extended_data[i % m_channels] + i / m_channels * bps, bps); + memcpy(audio + i * bps, m_frame->extended_data[i % m_channels] + i / m_channels * bps, bps); } - m_output_at -= len; + m_output_size -= len; for(int i = 0; i < m_channels; i++) { - memmove(m_decoded_frame->extended_data[i], - m_decoded_frame->extended_data[i] + len/m_channels, m_output_at/m_channels); + memmove(m_frame->extended_data[i], + m_frame->extended_data[i] + len / m_channels, m_output_size / m_channels); } } else { - memcpy(audio, m_decoded_frame->extended_data[0], len); - m_output_at -= len; - memmove(m_decoded_frame->extended_data[0], m_decoded_frame->extended_data[0] + len, m_output_at); + memcpy(audio, m_frame->extended_data[0], len); + m_output_size -= len; + memmove(m_frame->extended_data[0], m_frame->extended_data[0] + len, m_output_size); } - return len; -} - -qint64 DecoderFFmpeg::ffmpeg_decode() -{ - int out_size = 0; - int got_frame = 0; - if(m_pkt.stream_index == audioIndex) - { - int send_err = 0, receive_err = 0; - - if(m_temp_pkt.data) - { - if((send_err = avcodec_send_packet(c, &m_temp_pkt)) != 0) - { - qWarning("DecoderFFmpeg: avcodec_send_packet error: %d", send_err); - } - } - - int l = (send_err != 0) ? 0 : m_temp_pkt.size; - - if((receive_err = avcodec_receive_frame(c, m_decoded_frame)) != 0) - { - qWarning("DecoderFFmpeg: avcodec_receive_frame error: %d", receive_err); - if(send_err < 0 && receive_err < 0) - return -1; - - if(receive_err == AVERROR(EAGAIN)) - return 0; - } - else - { - got_frame = m_decoded_frame->pkt_size; - } - - if(got_frame) - out_size = av_samples_get_buffer_size(nullptr, c->channels, m_decoded_frame->nb_samples, - c->sample_fmt, 1); - else - out_size = 0; + if(!m_output_size) + av_frame_unref(m_frame); - if(c->bit_rate) - m_bitrate = c->bit_rate/1000; - if(l < 0) - { - return l; - } - m_temp_pkt.data += l; - m_temp_pkt.size -= l; - } - if (!m_temp_pkt.size && m_pkt.data) - av_packet_unref(&m_pkt); - - return out_size; + return len; } void DecoderFFmpeg::seek(qint64 pos) { int64_t timestamp = int64_t(pos) * AV_TIME_BASE / 1000; - if (ic->start_time != (qint64)AV_NOPTS_VALUE) - timestamp += ic->start_time; + if (m_formatContext->start_time != (qint64)AV_NOPTS_VALUE) + timestamp += m_formatContext->start_time; m_seekTime = timestamp; - av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(c); - av_packet_unref(&m_pkt); - m_temp_pkt.size = 0; + av_seek_frame(m_formatContext, -1, timestamp, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(m_codecContext); + av_packet_unref(m_pkt); + av_frame_unref(m_frame); + m_output_size = 0; + m_eof = false; } void DecoderFFmpeg::fillBuffer() { - while(!m_output_at || m_skipBytes > 0) + while(!m_output_size || m_skipBytes > 0) { - if(!m_temp_pkt.size) + if(!m_pkt->size && !m_eof) { - if (av_read_frame(ic, &m_pkt) < 0) + int read_error = av_read_frame(m_formatContext, m_pkt); + if(!read_error) { - m_temp_pkt.size = 0; - m_temp_pkt.data = nullptr; - } - m_temp_pkt.size = m_pkt.size; - m_temp_pkt.data = m_pkt.data; + if(m_pkt->stream_index != m_audioIndex) + { + av_packet_unref(m_pkt); + m_pkt->size = 0; + continue; + } - if(m_pkt.stream_index != audioIndex) + if(m_seekTime > 0 && m_codecContext->codec_id == AV_CODEC_ID_APE) + { + int64_t rescaledPts = av_rescale(m_pkt->pts, + AV_TIME_BASE * (int64_t) m_formatContext->streams[m_audioIndex]->time_base.num, + m_formatContext->streams[m_pkt->stream_index]->time_base.den); + m_skipBytes = (m_seekTime - rescaledPts) * m_codecContext->sample_rate / AV_TIME_BASE * audioParameters().frameSize(); + } + m_seekTime = -1; + } + else { - m_temp_pkt.size = 0; - if(m_pkt.data) + if(read_error != AVERROR_EOF) { - av_packet_unref(&m_pkt); - continue; + char errbuf[AV_ERROR_MAX_STRING_SIZE] = { 0 }; + av_strerror(read_error, errbuf, sizeof(errbuf)); + qWarning("DecoderFFmpeg: av_read_frame error: %s", errbuf); } - return; + m_eof = true; } + } - if(m_seekTime && c->codec_id == AV_CODEC_ID_APE) + int send_error = 0; + + if(m_pkt->size > 0) + { + if(!(send_error = avcodec_send_packet(m_codecContext, m_pkt))) { - int64_t rescaledPts = av_rescale(m_pkt.pts, - AV_TIME_BASE * (int64_t) - ic->streams[m_pkt.stream_index]->time_base.num, - ic->streams[m_pkt.stream_index]->time_base.den); - m_skipBytes = (m_seekTime - rescaledPts) * c->sample_rate * 4 / AV_TIME_BASE; + av_packet_unref(m_pkt); + m_pkt->size = 0; } - m_seekTime = 0; } - if(m_skipBytes > 0 && c->codec_id == AV_CODEC_ID_APE) + int recv_error = avcodec_receive_frame(m_codecContext, m_frame); + + if((m_eof || send_error < 0) && recv_error < 0) { - while (m_skipBytes > 0) + char errbuf[AV_ERROR_MAX_STRING_SIZE] = { 0 }; + if(!m_eof) + { + av_strerror(send_error, errbuf, sizeof(errbuf)); + qWarning("DecoderFFmpeg: avcodec_send_packet error: %s", errbuf); + av_strerror(recv_error, errbuf, sizeof(errbuf)); + qWarning("DecoderFFmpeg: avcodec_receive_frame error: %s", errbuf); + } + else { - m_output_at = ffmpeg_decode(); - if(m_output_at < 0) - break; - m_skipBytes -= m_output_at; + qDebug("DecoderFFmpeg: finished"); } + return; + } - if(m_skipBytes < 0) + if(!recv_error) + { + m_output_size = av_samples_get_buffer_size(nullptr, + m_codecContext->channels, + m_frame->nb_samples, + m_codecContext->sample_fmt, 1); + if(m_codecContext->bit_rate) + m_bitrate = m_codecContext->bit_rate / 1000; + + //hack for APE + if(m_skipBytes > 0 && m_output_size > 0) { - qint64 size = m_output_at; - m_output_at = - m_skipBytes; - m_output_at = m_output_at - (m_output_at % 4); + qint64 len = qMin(m_output_size, m_skipBytes); + m_skipBytes -= len; + m_output_size -= len; - if(av_sample_fmt_is_planar(c->sample_fmt) && m_channels > 1) + if(!m_output_size) { - memmove(m_decoded_frame->extended_data[0], - m_decoded_frame->extended_data[0] + (size - m_output_at)/2, m_output_at/2); - memmove(m_decoded_frame->extended_data[1], - m_decoded_frame->extended_data[1] + (size - m_output_at)/2, m_output_at/2); + av_frame_unref(m_frame); } - else + else if(m_output_size > 0) { - memmove(m_decoded_frame->extended_data[0], - m_decoded_frame->extended_data[0] + size - m_output_at, m_output_at); + if(av_sample_fmt_is_planar(m_codecContext->sample_fmt) && m_channels > 1) + { + for(int i = 0; i < m_channels; i++) + { + memmove(m_frame->extended_data[i], + m_frame->extended_data[i] + len / m_channels, m_output_size / m_channels); + } + } + else + { + memmove(m_frame->extended_data[0], m_frame->extended_data[0] + len, m_output_size); + } } - m_skipBytes = 0; } } - else - m_output_at = ffmpeg_decode(); - - if(m_output_at < 0) - { - m_output_at = 0; - m_temp_pkt.size = 0; - - if(m_pkt.data) - av_packet_unref(&m_pkt); - - m_pkt.data = nullptr; - m_temp_pkt.size = 0; - break; - } - else if(m_output_at == 0 && !m_pkt.data) - { - return; - } - else if(m_output_at == 0) - { - if(m_pkt.data) - av_packet_unref(&m_pkt); - - m_pkt.data = nullptr; - m_temp_pkt.size = 0; - continue; - } } } diff --git a/src/plugins/Input/ffmpeg/decoder_ffmpeg.h b/src/plugins/Input/ffmpeg/decoder_ffmpeg.h index a5748e394..5bea3901d 100644 --- a/src/plugins/Input/ffmpeg/decoder_ffmpeg.h +++ b/src/plugins/Input/ffmpeg/decoder_ffmpeg.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2006-2019 by Ilya Kotov * + * Copyright (C) 2006-2020 by Ilya Kotov * * forkotov02@ya.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -50,24 +50,23 @@ private: //helper functions void fillBuffer(); - AVFormatContext *ic; - AVCodecContext *c; - - int m_bitrate, audioIndex; + AVFormatContext *m_formatContext = nullptr; + AVCodecContext *m_codecContext = nullptr; + AVIOContext *m_stream = nullptr; + AVFrame *m_frame = nullptr; + int m_bitrate = 0, m_audioIndex = 0; QString m_path; - qint64 m_totalTime; - AVPacket m_pkt; - AVPacket m_temp_pkt; - qint64 m_output_at; - uchar *m_input_buf; - int64_t m_seekTime; - qint64 m_skipBytes; - int m_channels; + qint64 m_totalTime = 0; + AVPacket *m_pkt = nullptr; + qint64 m_output_size = 0; + uchar *m_input_buf = nullptr; + int64_t m_seekTime = -1; + qint64 m_skipBytes = 0; + int m_channels = 0; + bool m_eof = false; + - qint64 ffmpeg_decode(); - AVIOContext *m_stream; - AVFrame *m_decoded_frame; }; |
