int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_size) { int got_output; AVFrame *frame; if (!m_CodecCtx) return 0; /* allocate the input frame * sadly, we have to alloc/dealloc it everytime since we have no guarantee the * data argument will be constant over iterated calls and the frame needs to * setup pointers inside data */ frame = av_frame_alloc(); if (!frame) return 0; frame->nb_samples = m_CodecCtx->frame_size; frame->format = m_CodecCtx->sample_fmt; frame->channel_layout = m_CodecCtx->channel_layout; avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, in, in_size, 0); /* initialize the output packet */ av_init_packet(&m_Pkt); m_Pkt.size = out_size - IEC61937_DATA_OFFSET; m_Pkt.data = out + IEC61937_DATA_OFFSET; /* encode it */ int ret = avcodec_encode_audio2(m_CodecCtx, &m_Pkt, frame, &got_output); /* free temporary data */ av_frame_free(&frame); if (ret < 0 || !got_output) { CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Encoding failed"); return 0; } /* pack it into an IEC958 frame */ m_PackFunc(NULL, m_Pkt.size, out); /* free the packet */ av_free_packet(&m_Pkt); /* return the number of frames used */ return m_NeededFrames; }
int CAEEncoderFFmpeg::Encode(float *data, unsigned int frames) { if (!m_CodecCtx || frames < m_NeededFrames) return 0; /* encode it */ int size = m_dllAvCodec.avcodec_encode_audio(m_CodecCtx, m_Buffer + IEC61937_DATA_OFFSET, FF_MIN_BUFFER_SIZE, (short*)data); /* pack it into an IEC958 frame */ m_BufferSize = m_PackFunc(NULL, size, m_Buffer); if (m_BufferSize != m_OutputSize) { m_OutputSize = m_BufferSize; m_OutputRatio = (double)m_NeededFrames / m_OutputSize; } /* return the number of frames used */ return m_NeededFrames; }
int CAEEncoderFFmpeg::Encode(float *data, unsigned int frames) { int got_output; AVFrame *frame; const uint8_t *input = (const uint8_t*) data; if (!m_CodecCtx || frames < m_NeededFrames) return 0; /* size of the buffer sent to the encoder: either from the input data or after * conversion, in all cases it is in the m_CodecCtx->sample_fmt format */ int buf_size = av_samples_get_buffer_size(NULL, m_CodecCtx->channels, frames, m_CodecCtx->sample_fmt, 0); assert(buf_size>0); /* allocate the input frame * sadly, we have to alloc/dealloc it everytime since we have no guarantee the * data argument will be constant over iterated calls and the frame needs to * setup pointers inside data */ frame = av_frame_alloc(); if (!frame) return 0; frame->nb_samples = m_CodecCtx->frame_size; frame->format = m_CodecCtx->sample_fmt; frame->channel_layout = m_CodecCtx->channel_layout; if (m_NeedConversion) { if (!m_ResampBuffer || buf_size > m_ResampBufferSize) { m_ResampBuffer = (uint8_t*)av_realloc(m_ResampBuffer, buf_size); if (!m_ResampBuffer) { CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Failed to allocate %i bytes buffer for resampling", buf_size); av_frame_free(&frame); return 0; } m_ResampBufferSize = buf_size; } avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, m_ResampBuffer, buf_size, 0); /* important note: the '&input' here works because we convert from a packed * format (ie, interleaved). If it were to be used to convert from planar * formats (ie, non-interleaved, which is not currently supported by AE), * we would need to adapt it or it would segfault. */ if (swr_convert(m_SwrCtx, frame->extended_data, frames, &input, frames) < 0) { CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Resampling failed"); av_frame_free(&frame); return 0; } } else avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, input, buf_size, 0); /* initialize the output packet */ av_init_packet(&m_Pkt); m_Pkt.size = sizeof(m_Buffer) - IEC61937_DATA_OFFSET; m_Pkt.data = m_Buffer + IEC61937_DATA_OFFSET; /* encode it */ int ret = avcodec_encode_audio2(m_CodecCtx, &m_Pkt, frame, &got_output); /* free temporary data */ av_frame_free(&frame); if (ret < 0 || !got_output) { CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Encoding failed"); return 0; } /* pack it into an IEC958 frame */ m_BufferSize = m_PackFunc(NULL, m_Pkt.size, m_Buffer); if (m_BufferSize != m_OutputSize) { m_OutputSize = m_BufferSize; m_OutputRatio = (double)m_NeededFrames / m_OutputSize; } /* free the packet */ av_free_packet(&m_Pkt); /* return the number of frames used */ return m_NeededFrames; }
bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input) { Reset(); bool ac3 = CSettings::Get().GetBool("audiooutput.ac3passthrough"); AVCodec *codec = NULL; #if 0 /* the DCA encoder is currently useless for transcode, it creates a 196 kHz DTS-HD like mongrel which is useless for SPDIF */ bool dts = CSettings::Get().GetBool("audiooutput.dtspassthrough"); if (dts && (!ac3 || g_advancedSettings.m_audioTranscodeTo.Equals("dts"))) { m_CodecName = "DTS"; m_CodecID = AV_CODEC_ID_DTS; m_PackFunc = &CAEPackIEC61937::PackDTS_1024; m_BitRate = DTS_ENCODE_BITRATE; codec = avcodec_find_encoder(m_CodecID); } #endif /* fallback to ac3 if we support it, we might not have DTS support */ if (!codec && ac3) { m_CodecName = "AC3"; m_CodecID = AV_CODEC_ID_AC3; m_PackFunc = &CAEPackIEC61937::PackAC3; m_BitRate = AC3_ENCODE_BITRATE; codec = avcodec_find_encoder(m_CodecID); } /* check we got the codec */ if (!codec) return false; m_CodecCtx = avcodec_alloc_context3(codec); m_CodecCtx->bit_rate = m_BitRate; m_CodecCtx->sample_rate = format.m_sampleRate; m_CodecCtx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK; /* select a suitable data format */ if (codec->sample_fmts) { bool hasFloat = false; bool hasDouble = false; bool hasS32 = false; bool hasS16 = false; bool hasU8 = false; bool hasFloatP = false; bool hasUnknownFormat = false; for(int i = 0; codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; ++i) { switch (codec->sample_fmts[i]) { case AV_SAMPLE_FMT_FLT: hasFloat = true; break; case AV_SAMPLE_FMT_DBL: hasDouble = true; break; case AV_SAMPLE_FMT_S32: hasS32 = true; break; case AV_SAMPLE_FMT_S16: hasS16 = true; break; case AV_SAMPLE_FMT_U8 : hasU8 = true; break; case AV_SAMPLE_FMT_FLTP: if (allow_planar_input) hasFloatP = true; else hasUnknownFormat = true; break; case AV_SAMPLE_FMT_NONE: return false; default: hasUnknownFormat = true; break; } } if (hasFloat) { m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_FLT; format.m_dataFormat = AE_FMT_FLOAT; } else if (hasFloatP) { m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP; format.m_dataFormat = AE_FMT_FLOATP; } else if (hasDouble) { m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_DBL; format.m_dataFormat = AE_FMT_DOUBLE; } else if (hasS32) { m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_S32; format.m_dataFormat = AE_FMT_S32NE; } else if (hasS16) { m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_S16; format.m_dataFormat = AE_FMT_S16NE; } else if (hasU8) { m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_U8; format.m_dataFormat = AE_FMT_U8; } else if (hasUnknownFormat) { m_CodecCtx->sample_fmt = codec->sample_fmts[0]; format.m_dataFormat = AE_FMT_FLOAT; m_NeedConversion = true; CLog::Log(LOGNOTICE, "CAEEncoderFFmpeg::Initialize - Unknown audio format, it will be resampled."); } else { CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Initialize - Unable to find a suitable data format for the codec (%s)", m_CodecName.c_str()); return false; } } m_CodecCtx->channels = BuildChannelLayout(m_CodecCtx->channel_layout, m_Layout); /* open the codec */ if (avcodec_open2(m_CodecCtx, codec, NULL)) { av_freep(&m_CodecCtx); return false; } format.m_frames = m_CodecCtx->frame_size; format.m_frameSamples = m_CodecCtx->frame_size * m_CodecCtx->channels; format.m_frameSize = m_CodecCtx->channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); format.m_channelLayout = m_Layout; m_CurrentFormat = format; m_NeededFrames = format.m_frames; m_OutputSize = m_PackFunc(NULL, 0, m_Buffer); m_OutputRatio = (double)m_NeededFrames / m_OutputSize; m_SampleRateMul = 1.0 / (double)m_CodecCtx->sample_rate; if (m_NeedConversion) { m_SwrCtx = swr_alloc_set_opts(NULL, m_CodecCtx->channel_layout, m_CodecCtx->sample_fmt, m_CodecCtx->sample_rate, m_CodecCtx->channel_layout, AV_SAMPLE_FMT_FLT, m_CodecCtx->sample_rate, 0, NULL); if (!m_SwrCtx || swr_init(m_SwrCtx) < 0) { CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Initialize - Failed to initialise resampler."); return false; } } CLog::Log(LOGNOTICE, "CAEEncoderFFmpeg::Initialize - %s encoder ready", m_CodecName.c_str()); return true; }