2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #ifndef __STDC_CONSTANT_MACROS
22 #define __STDC_CONSTANT_MACROS
24 #ifndef __STDC_LIMIT_MACROS
25 #define __STDC_LIMIT_MACROS
30 #define INT64_C __int64
33 #include "EncoderFFmpeg.h"
34 #include "filesystem/File.h"
35 #include "utils/log.h"
36 #include "settings/Settings.h"
37 #include "utils/URIUtils.h"
39 /* AV_PKT_FLAG_KEY was named PKT_FLAG_KEY in older versions of libavcodec */
40 #ifndef AV_PKT_FLAG_KEY
41 #define AV_PKT_FLAG_KEY PKT_FLAG_KEY
44 CEncoderFFmpeg::CEncoderFFmpeg():
53 bool CEncoderFFmpeg::Init(const char* strFile, int iInChannels, int iInRate, int iInBits)
55 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllAvFormat.Load()) return false;
56 m_dllAvFormat.av_register_all();
57 m_dllAvCodec.avcodec_register_all();
59 CStdString filename = URIUtils::GetFileName(strFile);
60 AVOutputFormat *fmt = NULL;
61 fmt = m_dllAvFormat.av_guess_format(NULL, filename.c_str(), NULL);
64 CLog::Log(LOGERROR, "CEncoderFFmpeg::Init - Unable to guess the output format for the file %s", filename.c_str());
69 codec = m_dllAvCodec.avcodec_find_encoder(
70 strcmp(fmt->name, "ogg") == 0 ? AV_CODEC_ID_VORBIS : fmt->audio_codec
75 CLog::Log(LOGERROR, "CEncoderFFmpeg::Init - Unable to find a suitable FFmpeg encoder");
79 m_Format = m_dllAvFormat.avformat_alloc_context();
80 m_Format->pb = m_dllAvFormat.avio_alloc_context(m_BCBuffer, sizeof(m_BCBuffer), AVIO_FLAG_READ, this, NULL, MuxerReadPacket, NULL);
83 m_dllAvUtil.av_freep(&m_Format);
84 CLog::Log(LOGERROR, "CEncoderFFmpeg::Init - Failed to allocate ByteIOContext");
88 m_Format->oformat = fmt;
89 m_Format->bit_rate = CSettings::Get().GetInt("audiocds.bitrate") * 1000;
91 /* add a stream to it */
92 m_Stream = m_dllAvFormat.avformat_new_stream(m_Format, codec);
95 m_dllAvUtil.av_freep(&m_Format->pb);
96 m_dllAvUtil.av_freep(&m_Format);
97 CLog::Log(LOGERROR, "CEncoderFFmpeg::Init - Failed to allocate AVStream context");
101 /* set the stream's parameters */
102 m_CodecCtx = m_Stream->codec;
103 m_CodecCtx->codec_id = codec->id;
104 m_CodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
105 m_CodecCtx->bit_rate = m_Format->bit_rate;
106 m_CodecCtx->sample_rate = iInRate;
107 m_CodecCtx->channels = iInChannels;
108 m_CodecCtx->channel_layout = m_dllAvUtil.av_get_default_channel_layout(iInChannels);
109 m_CodecCtx->time_base = (AVRational){1, iInRate};
111 if(fmt->flags & AVFMT_GLOBALHEADER)
113 m_CodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
114 m_Format->flags |= CODEC_FLAG_GLOBAL_HEADER;
117 m_dllAvCodec.av_init_packet(&m_Pkt);
118 m_Pkt.stream_index = m_Stream->index;
119 m_Pkt.flags |= AV_PKT_FLAG_KEY;
123 case 8: m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_U8 ; break;
124 case 16: m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_S16; break;
125 case 32: m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_S32; break;
127 m_dllAvUtil.av_freep(&m_Stream);
128 m_dllAvUtil.av_freep(&m_Format->pb);
129 m_dllAvUtil.av_freep(&m_Format);
133 if (m_dllAvCodec.avcodec_open2(m_CodecCtx, codec, NULL))
135 CLog::Log(LOGERROR, "CEncoderFFmpeg::Init - Failed to open the codec");
136 m_dllAvUtil.av_freep(&m_Stream);
137 m_dllAvUtil.av_freep(&m_Format->pb);
138 m_dllAvUtil.av_freep(&m_Format);
142 /* calculate how many bytes we need per frame */
143 m_NeededFrames = m_CodecCtx->frame_size;
144 m_NeededBytes = m_NeededFrames * iInChannels * (iInBits / 8);
145 m_Buffer = new uint8_t[m_NeededBytes];
148 /* set input stream information and open the file */
149 if (!CEncoder::Init(strFile, iInChannels, iInRate, iInBits))
151 CLog::Log(LOGERROR, "CEncoderFFmpeg::Init - Failed to call CEncoder::Init");
153 m_dllAvUtil.av_freep(&m_Stream);
154 m_dllAvUtil.av_freep(&m_Format->pb);
155 m_dllAvUtil.av_freep(&m_Format);
160 SetTag("album" , m_strAlbum);
161 SetTag("album_artist", m_strArtist);
162 SetTag("genre" , m_strGenre);
163 SetTag("title" , m_strTitle);
164 SetTag("track" , m_strTrack);
165 SetTag("encoder" , "XBMC FFmpeg Encoder");
167 /* write the header */
168 if (m_dllAvFormat.avformat_write_header(m_Format, NULL) != 0)
170 CLog::Log(LOGERROR, "CEncoderFFmpeg::Init - Failed to write the header");
172 m_dllAvUtil.av_freep(&m_Stream);
173 m_dllAvUtil.av_freep(&m_Format->pb);
174 m_dllAvUtil.av_freep(&m_Format);
181 void CEncoderFFmpeg::SetTag(const CStdString tag, const CStdString value)
183 m_dllAvUtil.av_dict_set(&m_Format->metadata, tag.c_str(), value.c_str(), 0);
186 int CEncoderFFmpeg::MuxerReadPacket(void *opaque, uint8_t *buf, int buf_size)
188 CEncoderFFmpeg *enc = (CEncoderFFmpeg*)opaque;
189 if(enc->WriteStream(buf, buf_size) != buf_size)
191 CLog::Log(LOGERROR, "Error writing FFmpeg buffer to file");
197 int CEncoderFFmpeg::Encode(int nNumBytesRead, BYTE* pbtStream)
199 while(nNumBytesRead > 0)
201 unsigned int space = m_NeededBytes - m_BufferSize;
202 unsigned int copy = (unsigned int)nNumBytesRead > space ? space : nNumBytesRead;
204 memcpy(&m_Buffer[m_BufferSize], pbtStream, space);
205 m_BufferSize += copy;
207 nNumBytesRead -= copy;
209 /* only write full packets */
210 if (m_BufferSize == m_NeededBytes)
211 if (!WriteFrame()) return 0;
217 bool CEncoderFFmpeg::WriteFrame()
219 uint8_t outbuf[FF_MIN_BUFFER_SIZE];
222 encoded = m_dllAvCodec.avcodec_encode_audio(m_CodecCtx, outbuf, FF_MIN_BUFFER_SIZE, (short*)m_Buffer);
225 CLog::Log(LOGERROR, "CEncoderFFmpeg::WriteFrame - Error encoding audio");
230 m_Pkt.size = encoded;
232 if (m_CodecCtx->coded_frame && m_CodecCtx->coded_frame->pts != AV_NOPTS_VALUE)
233 m_Pkt.pts = m_dllAvUtil.av_rescale_q(m_CodecCtx->coded_frame->pts, m_Stream->time_base, m_CodecCtx->time_base);
235 if (m_dllAvFormat.av_write_frame(m_Format, &m_Pkt) < 0) {
236 CLog::Log(LOGERROR, "CEncoderFFMmpeg::WriteFrame - Failed to write the frame data");
243 bool CEncoderFFmpeg::Close()
246 /* if there is anything still in the buffer */
247 if (m_BufferSize > 0) {
248 /* zero the unused space so we dont encode random junk */
249 memset(&m_Buffer[m_BufferSize], 0, m_NeededBytes - m_BufferSize);
250 /* write any remaining data */
254 /* write the eof flag */
259 /* write the trailer */
260 m_dllAvFormat.av_write_trailer(m_Format);
265 m_dllAvCodec.avcodec_close(m_CodecCtx);
266 m_dllAvUtil.av_freep(&m_Stream );
267 m_dllAvUtil.av_freep(&m_Format->pb);
268 m_dllAvUtil.av_freep(&m_Format );
273 m_dllAvFormat.Unload();
274 m_dllAvUtil .Unload();
275 m_dllAvCodec .Unload();