00001
00002 #include <cstdio>
00003 #include <unistd.h>
00004 #include <string.h>
00005
00006 #include "mythcorecontext.h"
00007 #include "config.h"
00008
00009
00010 extern "C" {
00011 #include "libavutil/mem.h"
00012 #include "libavcodec/avcodec.h"
00013 }
00014
00015
00016 #include "audiooutputdigitalencoder.h"
00017 #include "audiooutpututil.h"
00018 #include "compat.h"
00019 #include "mythlogging.h"
00020
00021 #define LOC QString("DEnc: ")
00022
00023 AudioOutputDigitalEncoder::AudioOutputDigitalEncoder(void) :
00024 av_context(NULL),
00025 out(NULL), out_size(0),
00026 in(NULL), in_size(0),
00027 outlen(0), inlen(0),
00028 samples_per_frame(0),
00029 m_spdifenc(NULL)
00030 {
00031 out = (outbuf_t *)av_malloc(OUTBUFSIZE);
00032 if (out)
00033 {
00034 out_size = OUTBUFSIZE;
00035 }
00036 in = (inbuf_t *)av_malloc(INBUFSIZE);
00037 if (in)
00038 {
00039 in_size = INBUFSIZE;
00040 }
00041 }
00042
00043 AudioOutputDigitalEncoder::~AudioOutputDigitalEncoder()
00044 {
00045 Dispose();
00046 }
00047
00048 void AudioOutputDigitalEncoder::Dispose()
00049 {
00050 if (av_context)
00051 {
00052 avcodec_close(av_context);
00053 av_freep(&av_context);
00054 }
00055 if (out)
00056 {
00057 av_freep(&out);
00058 out_size = 0;
00059 }
00060 if (in)
00061 {
00062 av_freep(&in);
00063 in_size = 0;
00064 }
00065 if (m_spdifenc)
00066 {
00067 delete m_spdifenc;
00068 m_spdifenc = NULL;
00069 }
00070 }
00071
00072 void *AudioOutputDigitalEncoder::realloc(void *ptr,
00073 size_t old_size, size_t new_size)
00074 {
00075 if (!ptr)
00076 return ptr;
00077
00078
00079 void *new_ptr = av_malloc(new_size);
00080 if (!new_ptr)
00081 {
00082 av_free(ptr);
00083 return new_ptr;
00084 }
00085 memcpy(new_ptr, ptr, old_size);
00086 av_free(ptr);
00087 return new_ptr;
00088 }
00089
00090 bool AudioOutputDigitalEncoder::Init(
00091 CodecID codec_id, int bitrate, int samplerate, int channels)
00092 {
00093 AVCodec *codec;
00094 int ret;
00095
00096 LOG(VB_AUDIO, LOG_INFO, LOC +
00097 QString("Init codecid=%1, br=%2, sr=%3, ch=%4")
00098 .arg(ff_codec_id_string(codec_id)) .arg(bitrate)
00099 .arg(samplerate) .arg(channels));
00100
00101
00102 avcodeclock->lock();
00103 avcodec_register_all();
00104 avcodeclock->unlock();
00105 codec = avcodec_find_encoder_by_name("ac3_fixed");
00106 if (!codec)
00107 {
00108 LOG(VB_GENERAL, LOG_ERR, LOC + "Could not find codec");
00109 return false;
00110 }
00111
00112 av_context = avcodec_alloc_context3(codec);
00113 avcodec_get_context_defaults3(av_context, codec);
00114
00115 av_context->bit_rate = bitrate;
00116 av_context->sample_rate = samplerate;
00117 av_context->channels = channels;
00118 switch (channels)
00119 {
00120 case 1:
00121 av_context->channel_layout = AV_CH_LAYOUT_MONO;
00122 break;
00123 case 2:
00124 av_context->channel_layout = AV_CH_LAYOUT_STEREO;
00125 break;
00126 case 3:
00127 av_context->channel_layout = AV_CH_LAYOUT_SURROUND;
00128 break;
00129 case 4:
00130 av_context->channel_layout = AV_CH_LAYOUT_4POINT0;
00131 break;
00132 case 5:
00133 av_context->channel_layout = AV_CH_LAYOUT_5POINT0;
00134 break;
00135 default:
00136 av_context->channel_layout = AV_CH_LAYOUT_5POINT1;
00137 break;
00138 }
00139 av_context->sample_fmt = AV_SAMPLE_FMT_S16;
00140
00141
00142 ret = avcodec_open2(av_context, codec, NULL);
00143 if (ret < 0)
00144 {
00145 LOG(VB_GENERAL, LOG_ERR, LOC +
00146 "Could not open codec, invalid bitrate or samplerate");
00147
00148 Dispose();
00149 return false;
00150 }
00151
00152 if (m_spdifenc)
00153 {
00154 delete m_spdifenc;
00155 }
00156
00157 m_spdifenc = new SPDIFEncoder("spdif", CODEC_ID_AC3);
00158 if (!m_spdifenc->Succeeded())
00159 {
00160 Dispose();
00161 LOG(VB_GENERAL, LOG_ERR, LOC + "Could not create spdif muxer");
00162 return false;
00163 }
00164
00165 samples_per_frame = av_context->frame_size * av_context->channels;
00166
00167 LOG(VB_AUDIO, LOG_INFO, QString("DigitalEncoder::Init fs=%1, spf=%2")
00168 .arg(av_context->frame_size) .arg(samples_per_frame));
00169
00170 return true;
00171 }
00172
00173 size_t AudioOutputDigitalEncoder::Encode(void *buf, int len, AudioFormat format)
00174 {
00175
00176 int required_len = inlen + len / AudioOutputSettings::SampleSize(format) *
00177 AudioOutputSettings::SampleSize(FORMAT_S16);
00178 if (required_len > (int)in_size)
00179 {
00180 required_len = ((required_len / INBUFSIZE) + 1) * INBUFSIZE;
00181 LOG(VB_AUDIO, LOG_INFO, LOC +
00182 QString("low mem, reallocating in buffer from %1 to %2")
00183 .arg(in_size) .arg(required_len));
00184 inbuf_t *tmp = reinterpret_cast<inbuf_t*>
00185 (realloc(in, in_size, required_len));
00186 if (!tmp)
00187 {
00188 in = NULL;
00189 in_size = 0;
00190 LOG(VB_AUDIO, LOG_ERR, LOC +
00191 "AC-3 encode error, insufficient memory");
00192 return outlen;
00193 }
00194 in = tmp;
00195 in_size = required_len;
00196 }
00197 if (format != FORMAT_S16)
00198 {
00199 inlen += AudioOutputUtil::fromFloat(FORMAT_S16, (char *)in + inlen,
00200 buf, len);
00201 }
00202 else
00203 {
00204 memcpy((char *)in + inlen, buf, len);
00205 inlen += len;
00206 }
00207
00208 int frames = inlen / sizeof(inbuf_t) / samples_per_frame;
00209 int i = 0;
00210 AVFrame *frame = avcodec_alloc_frame();
00211
00212 while (i < frames)
00213 {
00214 AVPacket pkt;
00215 av_init_packet(&pkt);
00216 pkt.data = (uint8_t *)m_encodebuffer;
00217 pkt.size = sizeof(m_encodebuffer);
00218 frame->nb_samples = av_context->frame_size;
00219 frame->data[0] = (uint8_t *)(in + i * samples_per_frame);
00220 frame->pts = AV_NOPTS_VALUE;
00221 int got_packet = 0;
00222 int ret = avcodec_encode_audio2(av_context, &pkt, frame,
00223 &got_packet);
00224 int outsize = pkt.size;
00225
00226 if (ret < 0)
00227 {
00228 LOG(VB_AUDIO, LOG_ERR, LOC + "AC-3 encode error");
00229 return ret;
00230 }
00231 av_free_packet(&pkt);
00232 i++;
00233 if (!got_packet)
00234 continue;
00235
00236 if (!m_spdifenc)
00237 {
00238 m_spdifenc = new SPDIFEncoder("spdif", CODEC_ID_AC3);
00239 }
00240 m_spdifenc->WriteFrame((uint8_t *)m_encodebuffer, outsize);
00241
00242 required_len = outlen + m_spdifenc->GetProcessedSize();
00243 if (required_len > (int)out_size)
00244 {
00245 required_len = ((required_len / OUTBUFSIZE) + 1) * OUTBUFSIZE;
00246 LOG(VB_AUDIO, LOG_WARNING, LOC +
00247 QString("low mem, reallocating out buffer from %1 to %2")
00248 .arg(out_size) .arg(required_len));
00249 outbuf_t *tmp = reinterpret_cast<outbuf_t*>
00250 (realloc(out, out_size, required_len));
00251 if (!tmp)
00252 {
00253 out = NULL;
00254 out_size = 0;
00255 LOG(VB_AUDIO, LOG_ERR, LOC +
00256 "AC-3 encode error, insufficient memory");
00257 return outlen;
00258 }
00259 out = tmp;
00260 out_size = required_len;
00261 }
00262 int data_size = 0;
00263 m_spdifenc->GetData((uint8_t *)out + outlen, data_size);
00264 outlen += data_size;
00265 inlen -= samples_per_frame * sizeof(inbuf_t);
00266 }
00267 av_free(frame);
00268
00269 memmove(in, in + i * samples_per_frame, inlen);
00270 return outlen;
00271 }
00272
00273 size_t AudioOutputDigitalEncoder::GetFrames(void *ptr, int maxlen)
00274 {
00275 int len = std::min(maxlen, outlen);
00276 if (len != maxlen)
00277 {
00278 LOG(VB_AUDIO, LOG_INFO, LOC + "GetFrames: getting less than requested");
00279 }
00280 memcpy(ptr, out, len);
00281 outlen -= len;
00282 memmove(out, (char *)out + len, outlen);
00283 return len;
00284 }
00285
00286 void AudioOutputDigitalEncoder::clear()
00287 {
00288 inlen = outlen = 0;
00289 }