summaryrefslogtreecommitdiff
path: root/libavcodec/utils.c
diff options
context:
space:
mode:
authorJustin Ruggles <justin.ruggles@gmail.com>2011-12-18 13:20:15 -0500
committerJustin Ruggles <justin.ruggles@gmail.com>2012-01-15 21:24:17 -0500
commitb2c75b6e6320b1a399d76913f9d98c56f386f98b (patch)
tree72a0e973e1069acf8e9f84756742a116b430c4d9 /libavcodec/utils.c
parent5ee5fa021f32e0506bed6ebd183c807d5162bc72 (diff)
avcodec: Add avcodec_encode_audio2() as replacement for avcodec_encode_audio()
This allows audio encoders to optionally take an AVFrame as input and write encoded output to an AVPacket. This also adds AVCodec.encode2() which will also be usable by video and subtitle encoders once support is implemented in the public functions.
Diffstat (limited to 'libavcodec/utils.c')
-rw-r--r--libavcodec/utils.c246
1 files changed, 229 insertions, 17 deletions
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index c3faa76169..ff3f065064 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -25,6 +25,7 @@
* utils.
*/
+#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/crc.h"
#include "libavutil/mathematics.h"
@@ -101,6 +102,16 @@ void avcodec_init(void)
dsputil_static_init();
}
+static av_always_inline int codec_is_encoder(AVCodec *codec)
+{
+ return codec && (codec->encode || codec->encode2);
+}
+
+static av_always_inline int codec_is_decoder(AVCodec *codec)
+{
+ return codec && codec->decode;
+}
+
void avcodec_register(AVCodec *codec)
{
AVCodec **p;
@@ -690,7 +701,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVD
/* if the decoder init function was already called previously,
free the already allocated subtitle_header before overwriting it */
- if (codec->decode)
+ if (codec_is_decoder(codec))
av_freep(&avctx->subtitle_header);
#define SANE_NB_CHANNELS 128U
@@ -738,7 +749,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVD
ret = AVERROR(EINVAL);
goto free_and_end;
}
- if (avctx->codec->encode) {
+ if (codec_is_encoder(avctx->codec)) {
int i;
if (avctx->codec->sample_fmts) {
for (i = 0; avctx->codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++)
@@ -812,20 +823,221 @@ free_and_end:
goto end;
}
-int attribute_align_arg avcodec_encode_audio(AVCodecContext *avctx, uint8_t *buf, int buf_size,
- const short *samples)
+int ff_alloc_packet(AVPacket *avpkt, int size)
{
- if(buf_size < FF_MIN_BUFFER_SIZE && 0){
- av_log(avctx, AV_LOG_ERROR, "buffer smaller than minimum size\n");
- return -1;
+ if (size > INT_MAX - FF_INPUT_BUFFER_PADDING_SIZE)
+ return AVERROR(EINVAL);
+
+ if (avpkt->data) {
+ uint8_t *pkt_data;
+ int pkt_size;
+
+ if (avpkt->size < size)
+ return AVERROR(EINVAL);
+
+ pkt_data = avpkt->data;
+ pkt_size = avpkt->size;
+ av_init_packet(avpkt);
+ avpkt->data = pkt_data;
+ avpkt->size = pkt_size;
+ return 0;
+ } else {
+ return av_new_packet(avpkt, size);
}
- if((avctx->codec->capabilities & CODEC_CAP_DELAY) || samples){
- int ret = avctx->codec->encode(avctx, buf, buf_size, samples);
- avctx->frame_number++;
- return ret;
- }else
+}
+
+int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx,
+ AVPacket *avpkt,
+ const AVFrame *frame,
+ int *got_packet_ptr)
+{
+ int ret;
+ int user_packet = !!avpkt->data;
+ int nb_samples;
+
+ if (!(avctx->codec->capabilities & CODEC_CAP_DELAY) && !frame) {
+ av_init_packet(avpkt);
+ avpkt->size = 0;
return 0;
+ }
+
+ /* check for valid frame size */
+ if (frame) {
+ nb_samples = frame->nb_samples;
+ if (avctx->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) {
+ if (nb_samples > avctx->frame_size)
+ return AVERROR(EINVAL);
+ } else if (!(avctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) {
+ if (nb_samples != avctx->frame_size)
+ return AVERROR(EINVAL);
+ }
+ } else {
+ nb_samples = avctx->frame_size;
+ }
+
+ if (avctx->codec->encode2) {
+ *got_packet_ptr = 0;
+ ret = avctx->codec->encode2(avctx, avpkt, frame, got_packet_ptr);
+ if (!ret && *got_packet_ptr &&
+ !(avctx->codec->capabilities & CODEC_CAP_DELAY)) {
+ avpkt->pts = frame->pts;
+ avpkt->duration = av_rescale_q(frame->nb_samples,
+ (AVRational){ 1, avctx->sample_rate },
+ avctx->time_base);
+ }
+ } else {
+ /* for compatibility with encoders not supporting encode2(), we need to
+ allocate a packet buffer if the user has not provided one or check
+ the size otherwise */
+ int fs_tmp = 0;
+ int buf_size = avpkt->size;
+ if (!user_packet) {
+ if (avctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) {
+ av_assert0(av_get_bits_per_sample(avctx->codec_id) != 0);
+ buf_size = nb_samples * avctx->channels *
+ av_get_bits_per_sample(avctx->codec_id) / 8;
+ } else {
+ /* this is a guess as to the required size.
+ if an encoder needs more than this, it should probably
+ implement encode2() */
+ buf_size = 2 * avctx->frame_size * avctx->channels *
+ av_get_bytes_per_sample(avctx->sample_fmt);
+ buf_size += FF_MIN_BUFFER_SIZE;
+ }
+ }
+ if ((ret = ff_alloc_packet(avpkt, buf_size)))
+ return ret;
+
+ /* Encoders using AVCodec.encode() that support
+ CODEC_CAP_SMALL_LAST_FRAME require avctx->frame_size to be set to
+ the smaller size when encoding the last frame.
+ This code can be removed once all encoders supporting
+ CODEC_CAP_SMALL_LAST_FRAME use encode2() */
+ if ((avctx->codec->capabilities & CODEC_CAP_SMALL_LAST_FRAME) &&
+ nb_samples < avctx->frame_size) {
+ fs_tmp = avctx->frame_size;
+ avctx->frame_size = nb_samples;
+ }
+
+ /* encode the frame */
+ ret = avctx->codec->encode(avctx, avpkt->data, avpkt->size,
+ frame ? frame->data[0] : NULL);
+ if (ret >= 0) {
+ if (!ret) {
+ /* no output. if the packet data was allocated by libavcodec,
+ free it */
+ if (!user_packet)
+ av_freep(&avpkt->data);
+ } else {
+ if (avctx->coded_frame)
+ avpkt->pts = avctx->coded_frame->pts;
+ /* Set duration for final small packet. This can be removed
+ once all encoders supporting CODEC_CAP_SMALL_LAST_FRAME use
+ encode2() */
+ if (fs_tmp) {
+ avpkt->duration = av_rescale_q(avctx->frame_size,
+ (AVRational){ 1, avctx->sample_rate },
+ avctx->time_base);
+ }
+ }
+ avpkt->size = ret;
+ *got_packet_ptr = (ret > 0);
+ ret = 0;
+ }
+
+ if (fs_tmp)
+ avctx->frame_size = fs_tmp;
+ }
+ if (!ret)
+ avctx->frame_number++;
+
+ /* NOTE: if we add any audio encoders which output non-keyframe packets,
+ this needs to be moved to the encoders, but for now we can do it
+ here to simplify things */
+ avpkt->flags |= AV_PKT_FLAG_KEY;
+
+ return ret;
+}
+
+#if FF_API_OLD_DECODE_AUDIO
+int attribute_align_arg avcodec_encode_audio(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size,
+ const short *samples)
+{
+ AVPacket pkt;
+ AVFrame frame0;
+ AVFrame *frame;
+ int ret, samples_size, got_packet;
+
+ av_init_packet(&pkt);
+ pkt.data = buf;
+ pkt.size = buf_size;
+
+ if (samples) {
+ frame = &frame0;
+ avcodec_get_frame_defaults(frame);
+
+ if (avctx->frame_size) {
+ frame->nb_samples = avctx->frame_size;
+ } else {
+ /* if frame_size is not set, the number of samples must be
+ calculated from the buffer size */
+ int64_t nb_samples;
+ if (!av_get_bits_per_sample(avctx->codec_id)) {
+ av_log(avctx, AV_LOG_ERROR, "avcodec_encode_audio() does not "
+ "support this codec\n");
+ return AVERROR(EINVAL);
+ }
+ nb_samples = (int64_t)buf_size * 8 /
+ (av_get_bits_per_sample(avctx->codec_id) *
+ avctx->channels);
+ if (nb_samples >= INT_MAX)
+ return AVERROR(EINVAL);
+ frame->nb_samples = nb_samples;
+ }
+
+ /* it is assumed that the samples buffer is large enough based on the
+ relevant parameters */
+ samples_size = av_samples_get_buffer_size(NULL, avctx->channels,
+ frame->nb_samples,
+ avctx->sample_fmt, 1);
+ if ((ret = avcodec_fill_audio_frame(frame, avctx->channels,
+ avctx->sample_fmt,
+ samples, samples_size, 1)))
+ return ret;
+
+ /* fabricate frame pts from sample count.
+ this is needed because the avcodec_encode_audio() API does not have
+ a way for the user to provide pts */
+ frame->pts = av_rescale_q(avctx->internal->sample_count,
+ (AVRational){ 1, avctx->sample_rate },
+ avctx->time_base);
+ avctx->internal->sample_count += frame->nb_samples;
+ } else {
+ frame = NULL;
+ }
+
+ got_packet = 0;
+ ret = avcodec_encode_audio2(avctx, &pkt, frame, &got_packet);
+ if (!ret && got_packet && avctx->coded_frame) {
+ avctx->coded_frame->pts = pkt.pts;
+ avctx->coded_frame->key_frame = !!(pkt.flags & AV_PKT_FLAG_KEY);
+ }
+ /* free any side data since we cannot return it */
+ if (pkt.side_data_elems > 0) {
+ int i;
+ for (i = 0; i < pkt.side_data_elems; i++)
+ av_free(pkt.side_data[i].data);
+ av_freep(&pkt.side_data);
+ pkt.side_data_elems = 0;
+ }
+
+ if (frame && frame->extended_data != frame->data)
+ av_free(frame->extended_data);
+
+ return ret ? ret : pkt.size;
}
+#endif
int attribute_align_arg avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size,
const AVFrame *pict)
@@ -1077,7 +1289,7 @@ av_cold int avcodec_close(AVCodecContext *avctx)
av_opt_free(avctx->priv_data);
av_opt_free(avctx);
av_freep(&avctx->priv_data);
- if(avctx->codec && avctx->codec->encode)
+ if (codec_is_encoder(avctx->codec))
av_freep(&avctx->extradata);
avctx->codec = NULL;
avctx->active_thread_type = 0;
@@ -1095,7 +1307,7 @@ AVCodec *avcodec_find_encoder(enum CodecID id)
AVCodec *p, *experimental=NULL;
p = first_avcodec;
while (p) {
- if (p->encode != NULL && p->id == id) {
+ if (codec_is_encoder(p) && p->id == id) {
if (p->capabilities & CODEC_CAP_EXPERIMENTAL && !experimental) {
experimental = p;
} else
@@ -1113,7 +1325,7 @@ AVCodec *avcodec_find_encoder_by_name(const char *name)
return NULL;
p = first_avcodec;
while (p) {
- if (p->encode != NULL && strcmp(name,p->name) == 0)
+ if (codec_is_encoder(p) && strcmp(name,p->name) == 0)
return p;
p = p->next;
}
@@ -1125,7 +1337,7 @@ AVCodec *avcodec_find_decoder(enum CodecID id)
AVCodec *p;
p = first_avcodec;
while (p) {
- if (p->decode != NULL && p->id == id)
+ if (codec_is_decoder(p) && p->id == id)
return p;
p = p->next;
}
@@ -1139,7 +1351,7 @@ AVCodec *avcodec_find_decoder_by_name(const char *name)
return NULL;
p = first_avcodec;
while (p) {
- if (p->decode != NULL && strcmp(name,p->name) == 0)
+ if (codec_is_decoder(p) && strcmp(name,p->name) == 0)
return p;
p = p->next;
}