/*************************************************************************************** * * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. * * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved. * * Redistribution and use in binary forms, with or without modification, are permitted. * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. * ****************************************************************************************/ #include "sys_inc.h" #include "audio_decoder.h" #include "avcodec_mutex.h" #include "media_codec.h" CAudioDecoder::CAudioDecoder() { m_bInited = FALSE; m_nSamplerate = 0; m_nChannels = 0; m_pCodec = NULL; m_pContext = NULL; m_pFrame = NULL; m_pResampleFrame = NULL; m_pSwrCtx = NULL; m_nDstFormat = AV_SAMPLE_FMT_S16; m_pCallback = NULL; m_pUserdata = NULL; } CAudioDecoder::~CAudioDecoder() { uninit(); } BOOL CAudioDecoder::init(enum AVCodecID codec, int samplerate, int channels, int bitpersample) { m_pCodec = avcodec_find_decoder(codec); if (m_pCodec == NULL) { log_print(HT_LOG_ERR, "%s, m_pCodec is NULL\r\n", __FUNCTION__); return FALSE; } m_pContext = avcodec_alloc_context3(m_pCodec); if (NULL == m_pContext) { log_print(HT_LOG_ERR, "%s, avcodec_alloc_context3 failed\r\n", __FUNCTION__); return FALSE; } m_pContext->sample_rate = samplerate; m_pContext->channels = channels; m_pContext->channel_layout = av_get_default_channel_layout(channels); if (AV_CODEC_ID_ADPCM_G726 == codec) { if (0 == bitpersample) { bitpersample = 2; } m_pContext->bits_per_coded_sample = bitpersample; m_pContext->bit_rate = bitpersample * 8000; } if (avcodec_thread_open(m_pContext, m_pCodec, NULL) < 0) { log_print(HT_LOG_ERR, "%s, avcodec_thread_open failed\r\n", __FUNCTION__); return FALSE; } if (m_pContext->sample_fmt != m_nDstFormat) { m_pSwrCtx = swr_alloc_set_opts(NULL, av_get_default_channel_layout(channels), m_nDstFormat, samplerate, av_get_default_channel_layout(channels), m_pContext->sample_fmt, samplerate, 0, NULL); swr_init(m_pSwrCtx); } m_pFrame = av_frame_alloc(); if (NULL == m_pFrame) { log_print(HT_LOG_ERR, "%s, av_frame_alloc failed\r\n", __FUNCTION__); return FALSE; } m_nSamplerate = samplerate; m_nChannels = channels; m_bInited = TRUE; return TRUE; } BOOL CAudioDecoder::init(int codec, int samplerate, int channels, int bitpersample) { return init(to_audio_avcodecid(codec), samplerate, channels, bitpersample); } BOOL CAudioDecoder::decode(uint8 * data, int len, int64_t pts) { AVPacket packet; av_init_packet(&packet); packet.data = data; packet.size = len; packet.pts = packet.dts = pts; return decode(&packet); } BOOL CAudioDecoder::decode(AVPacket *pkt) { int ret; if (!m_bInited) { return FALSE; } /* send the packet with the compressed data to the decoder */ ret = avcodec_send_packet(m_pContext, pkt); if (ret < 0) { log_print(HT_LOG_ERR, "%s, error submitting the packet to the decoder\r\n", __FUNCTION__); return FALSE; } /* read all the output frames (in general there may be any number of them */ while (ret >= 0) { ret = avcodec_receive_frame(m_pContext, m_pFrame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { return TRUE; } else if (ret < 0) { log_print(HT_LOG_ERR, "%s, error during decoding\r\n", __FUNCTION__); return FALSE; } render(m_pFrame); av_frame_unref(m_pFrame); } return TRUE; } void CAudioDecoder::flush() { if (NULL == m_pContext || NULL == m_pContext->codec || !(m_pContext->codec->capabilities | AV_CODEC_CAP_DELAY)) { return; } decode(NULL); } void CAudioDecoder::uninit() { flush(); if (m_pContext) { avcodec_thread_close(m_pContext); avcodec_free_context(&m_pContext); } if (m_pFrame) { av_frame_free(&m_pFrame); } if (m_pResampleFrame) { av_frame_free(&m_pResampleFrame); } if (m_pSwrCtx) { swr_free(&m_pSwrCtx); } m_bInited = FALSE; } void CAudioDecoder::render(AVFrame * frame) { if (NULL == frame) { return; } if (m_pSwrCtx) { if (NULL == m_pResampleFrame) { m_pResampleFrame = av_frame_alloc(); if (NULL == m_pResampleFrame) { return; } } m_pResampleFrame->sample_rate = m_nSamplerate; m_pResampleFrame->format = m_nDstFormat; m_pResampleFrame->channels = m_nChannels; m_pResampleFrame->channel_layout = av_get_default_channel_layout(m_nChannels); int swrret = swr_convert_frame(m_pSwrCtx, m_pResampleFrame, frame); if (swrret == 0) { if (m_pCallback) { m_pResampleFrame->pts = frame->pts; m_pResampleFrame->pkt_dts = frame->pkt_dts; m_pCallback(m_pResampleFrame, m_pUserdata); } } av_frame_unref(m_pResampleFrame); } else if (m_pCallback) { m_pCallback(frame, m_pUserdata); } }