mirror of https://github.com/FFmpeg/FFmpeg.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
5.0 KiB
149 lines
5.0 KiB
/* |
|
* Interface to libshine for mp3 encoding |
|
* Copyright (c) 2012 Paul B Mahol |
|
* |
|
* This file is part of FFmpeg. |
|
* |
|
* FFmpeg is free software; you can redistribute it and/or |
|
* modify it under the terms of the GNU Lesser General Public |
|
* License as published by the Free Software Foundation; either |
|
* version 2.1 of the License, or (at your option) any later version. |
|
* |
|
* FFmpeg is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
* Lesser General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU Lesser General Public |
|
* License along with FFmpeg; if not, write to the Free Software |
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
*/ |
|
|
|
#include <shine/layer3.h> |
|
|
|
#include "libavutil/channel_layout.h" |
|
#include "libavutil/intreadwrite.h" |
|
#include "audio_frame_queue.h" |
|
#include "avcodec.h" |
|
#include "codec_internal.h" |
|
#include "encode.h" |
|
#include "mpegaudio.h" |
|
#include "mpegaudiodecheader.h" |
|
|
|
#define BUFFER_SIZE (4096 * 20) |
|
|
|
typedef struct SHINEContext { |
|
shine_config_t config; |
|
shine_t shine; |
|
uint8_t buffer[BUFFER_SIZE]; |
|
int buffer_index; |
|
AudioFrameQueue afq; |
|
} SHINEContext; |
|
|
|
static av_cold int libshine_encode_init(AVCodecContext *avctx) |
|
{ |
|
SHINEContext *s = avctx->priv_data; |
|
|
|
shine_set_config_mpeg_defaults(&s->config.mpeg); |
|
if (avctx->bit_rate) |
|
s->config.mpeg.bitr = avctx->bit_rate / 1000; |
|
s->config.mpeg.mode = avctx->ch_layout.nb_channels == 2 ? STEREO : MONO; |
|
s->config.wave.samplerate = avctx->sample_rate; |
|
s->config.wave.channels = avctx->ch_layout.nb_channels == 2 ? PCM_STEREO : PCM_MONO; |
|
if (shine_check_config(s->config.wave.samplerate, s->config.mpeg.bitr) < 0) { |
|
av_log(avctx, AV_LOG_ERROR, "invalid configuration\n"); |
|
return AVERROR(EINVAL); |
|
} |
|
s->shine = shine_initialise(&s->config); |
|
if (!s->shine) |
|
return AVERROR(ENOMEM); |
|
avctx->frame_size = shine_samples_per_pass(s->shine); |
|
ff_af_queue_init(avctx, &s->afq); |
|
return 0; |
|
} |
|
|
|
static int libshine_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, |
|
const AVFrame *frame, int *got_packet_ptr) |
|
{ |
|
SHINEContext *s = avctx->priv_data; |
|
MPADecodeHeader hdr; |
|
unsigned char *data; |
|
int written; |
|
int ret, len; |
|
|
|
if (frame) |
|
data = shine_encode_buffer(s->shine, (int16_t **)frame->data, &written); |
|
else |
|
data = shine_flush(s->shine, &written); |
|
if (written < 0) |
|
return -1; |
|
if (written > 0) { |
|
if (s->buffer_index + written > BUFFER_SIZE) { |
|
av_log(avctx, AV_LOG_ERROR, "internal buffer too small\n"); |
|
return AVERROR_BUG; |
|
} |
|
memcpy(s->buffer + s->buffer_index, data, written); |
|
s->buffer_index += written; |
|
} |
|
if (frame) { |
|
if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) |
|
return ret; |
|
} |
|
|
|
if (s->buffer_index < 4 || !s->afq.frame_count) |
|
return 0; |
|
if (avpriv_mpegaudio_decode_header(&hdr, AV_RB32(s->buffer))) { |
|
av_log(avctx, AV_LOG_ERROR, "free format output not supported\n"); |
|
return -1; |
|
} |
|
|
|
len = hdr.frame_size; |
|
if (len <= s->buffer_index) { |
|
if ((ret = ff_get_encode_buffer(avctx, avpkt, len, 0))) |
|
return ret; |
|
memcpy(avpkt->data, s->buffer, len); |
|
s->buffer_index -= len; |
|
memmove(s->buffer, s->buffer + len, s->buffer_index); |
|
|
|
ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, |
|
&avpkt->duration); |
|
|
|
*got_packet_ptr = 1; |
|
} |
|
return 0; |
|
} |
|
|
|
static av_cold int libshine_encode_close(AVCodecContext *avctx) |
|
{ |
|
SHINEContext *s = avctx->priv_data; |
|
|
|
ff_af_queue_close(&s->afq); |
|
shine_close(s->shine); |
|
return 0; |
|
} |
|
|
|
static const int libshine_sample_rates[] = { |
|
44100, 48000, 32000, 0 |
|
}; |
|
|
|
const FFCodec ff_libshine_encoder = { |
|
.p.name = "libshine", |
|
CODEC_LONG_NAME("libshine MP3 (MPEG audio layer 3)"), |
|
.p.type = AVMEDIA_TYPE_AUDIO, |
|
.p.id = AV_CODEC_ID_MP3, |
|
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, |
|
.caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, |
|
.priv_data_size = sizeof(SHINEContext), |
|
.init = libshine_encode_init, |
|
FF_CODEC_ENCODE_CB(libshine_encode_frame), |
|
.close = libshine_encode_close, |
|
.p.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16P, |
|
AV_SAMPLE_FMT_NONE }, |
|
.p.supported_samplerates = libshine_sample_rates, |
|
CODEC_OLD_CHANNEL_LAYOUTS(AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO) |
|
.p.ch_layouts = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO, |
|
AV_CHANNEL_LAYOUT_STEREO, |
|
{ 0 }, |
|
}, |
|
.p.wrapper_name = "libshine", |
|
};
|
|
|