[FFmpeg-devel] [PATCH v2 1/3] avcodec/avpacket: extend AVFrame wrapping in AVPacket
Muhammad Faiz
mfcc64 at gmail.com
Sun Nov 15 09:51:30 CET 2015
add AV_PKT_FLAG_FRAME
add av_packet_encode_frame()
add av_packet_decode_frame()
add av_packet_get_frame()
use pointer to AVFrame instead
properly padded with AV_INPUT_BUFFER_PADDING_SIZE
modify wrapped_avframe encoder
implement wrapped_avframe decoder
implement wrapped_avframe_audio encoder/decoder
fix avformat/yuv4mpegenc to use av_packet_get_frame()
patch attached
-------------- next part --------------
From ae6b2c45faac830636602a696925566db03541a2 Mon Sep 17 00:00:00 2001
From: Muhammad Faiz <mfcc64 at gmail.com>
Date: Sun, 15 Nov 2015 12:06:12 +0700
Subject: [PATCH v2 1/3] avcodec/avpacket: extend AVFrame wrapping in AVPacket
add AV_PKT_FLAG_FRAME
add av_packet_encode_frame()
add av_packet_decode_frame()
add av_packet_get_frame()
use pointer to AVFrame instead
properly padded with AV_INPUT_BUFFER_PADDING_SIZE
modify wrapped_avframe encoder
implement wrapped_avframe decoder
implement wrapped_avframe_audio encoder/decoder
fix avformat/yuv4mpegenc to use av_packet_get_frame()
---
doc/APIchanges | 5 +++
libavcodec/Makefile | 3 ++
libavcodec/allcodecs.c | 3 +-
libavcodec/avcodec.h | 29 ++++++++++++++++
libavcodec/avpacket.c | 63 ++++++++++++++++++++++++++++++++++-
libavcodec/codec_desc.c | 7 ++++
libavcodec/version.h | 2 +-
libavcodec/wrapped_avframe.c | 78 ++++++++++++++++++++++++++++++++++----------
libavformat/yuv4mpegenc.c | 5 +--
9 files changed, 173 insertions(+), 22 deletions(-)
diff --git a/doc/APIchanges b/doc/APIchanges
index 14b96ce..9efd44e 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,11 @@ libavutil: 2015-08-28
API changes, most recent first:
+2015-11-15 - lavc 57.16.100 - avcodec.h
+ Add AV_PKT_FLAG_FRAME.
+ Add av_packet_encode_frame(), av_packet_decode_frame(),
+ and av_packet_get_frame().
+
2015-10-29 - lavc 57.12.100 / 57.8.0 - avcodec.h
xxxxxx - Deprecate av_free_packet(). Use av_packet_unref() as replacement,
it resets the packet in a more consistent way.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 68a573f..65d8621 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -577,7 +577,10 @@ OBJS-$(CONFIG_WMV2_ENCODER) += wmv2enc.o wmv2.o \
msmpeg4.o msmpeg4enc.o msmpeg4data.o
OBJS-$(CONFIG_WNV1_DECODER) += wnv1.o
OBJS-$(CONFIG_WS_SND1_DECODER) += ws-snd1.o
+OBJS-$(CONFIG_WRAPPED_AVFRAME_DECODER) += wrapped_avframe.o
OBJS-$(CONFIG_WRAPPED_AVFRAME_ENCODER) += wrapped_avframe.o
+OBJS-$(CONFIG_WRAPPED_AVFRAME_AUDIO_DECODER) += wrapped_avframe.o
+OBJS-$(CONFIG_WRAPPED_AVFRAME_AUDIO_ENCODER) += wrapped_avframe.o
OBJS-$(CONFIG_XAN_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_XAN_WC3_DECODER) += xan.o
OBJS-$(CONFIG_XAN_WC4_DECODER) += xxan.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 9f60d7c..836fd20 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -342,7 +342,7 @@ void avcodec_register_all(void)
REGISTER_DECODER(VP9, vp9);
REGISTER_DECODER(VQA, vqa);
REGISTER_DECODER(WEBP, webp);
- REGISTER_ENCODER(WRAPPED_AVFRAME, wrapped_avframe);
+ REGISTER_ENCDEC (WRAPPED_AVFRAME, wrapped_avframe);
REGISTER_ENCDEC (WMV1, wmv1);
REGISTER_ENCDEC (WMV2, wmv2);
REGISTER_DECODER(WMV3, wmv3);
@@ -446,6 +446,7 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (WMAV1, wmav1);
REGISTER_ENCDEC (WMAV2, wmav2);
REGISTER_DECODER(WMAVOICE, wmavoice);
+ REGISTER_ENCDEC (WRAPPED_AVFRAME_AUDIO, wrapped_avframe_audio);
REGISTER_DECODER(WS_SND1, ws_snd1);
REGISTER_DECODER(XMA1, xma1);
REGISTER_DECODER(XMA2, xma2);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 1af17ed..a318dc5 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -550,6 +550,7 @@ enum AVCodecID {
* stream (only used by libavformat) */
AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information.
AV_CODEC_ID_WRAPPED_AVFRAME = 0x21001, ///< Passthrough codec, AVFrames wrapped in AVPacket
+ AV_CODEC_ID_WRAPPED_AVFRAME_AUDIO = 0x21002,
};
/**
@@ -1442,6 +1443,7 @@ typedef struct AVPacket {
} AVPacket;
#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe
#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted
+#define AV_PKT_FLAG_FRAME 0x0004 ///< The packet contains an AVFrame frame
enum AVSideDataParamChangeFlags {
AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001,
@@ -4103,6 +4105,33 @@ int av_packet_copy_props(AVPacket *dst, const AVPacket *src);
void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);
/**
+ * Encode frame to packet.
+ *
+ * @param pkt destination packet
+ * @param frame source frame
+ * @return 0 on success, a negative AVERROR on failure
+ */
+int av_packet_encode_frame(AVPacket *pkt, const AVFrame *frame);
+
+/**
+ * Decode frame from packet.
+ *
+ * @param pkt source packet
+ * @param frame destination frame
+ * @return 0 on success, a negative AVERROR on failure
+ */
+int av_packet_decode_frame(const AVPacket *pkt, AVFrame *frame);
+
+/**
+ * Get the underlying frame of packet.
+ *
+ * @param pkt packet
+ * @return a pointer to the underlying frame on success,
+ * NULL when pkt does not contain valid AVFrame
+ */
+const AVFrame *av_packet_get_frame(const AVPacket *pkt);
+
+/**
* @}
*/
diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c
index 1cc10eb..fbb6508 100644
--- a/libavcodec/avpacket.c
+++ b/libavcodec/avpacket.c
@@ -100,7 +100,7 @@ int av_new_packet(AVPacket *pkt, int size)
void av_shrink_packet(AVPacket *pkt, int size)
{
- if (pkt->size <= size)
+ if (pkt->size <= size || pkt->flags & AV_PKT_FLAG_FRAME)
return;
pkt->size = size;
memset(pkt->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
@@ -110,6 +110,10 @@ int av_grow_packet(AVPacket *pkt, int grow_by)
{
int new_size;
av_assert0((unsigned)pkt->size <= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE);
+
+ if (pkt->flags & AV_PKT_FLAG_FRAME)
+ return AVERROR(EINVAL);
+
if (!pkt->size)
return av_new_packet(pkt, grow_by);
if ((unsigned)grow_by >
@@ -621,3 +625,60 @@ int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, i
return 0;
}
+
+static void packet_frame_release_buffer(void *unused, uint8_t *data)
+{
+ av_frame_free((AVFrame **)data);
+ av_freep(&data);
+}
+
+int av_packet_encode_frame(AVPacket *pkt, const AVFrame *frame)
+{
+ AVFrame **data = NULL;
+ int ret = AVERROR(ENOMEM);
+
+ if (!(data = av_mallocz(sizeof(*data) + AV_INPUT_BUFFER_PADDING_SIZE)))
+ goto fail;
+
+ if (!(*data = av_frame_clone(frame)))
+ goto fail;
+
+ /* set all timestamps to frame->pts */
+ (*data)->pkt_pts = (*data)->pkt_dts = frame->pts;
+ av_frame_set_best_effort_timestamp(*data, frame->pts);
+
+ pkt->buf = av_buffer_create((uint8_t *)data, sizeof(*data) + AV_INPUT_BUFFER_PADDING_SIZE,
+ packet_frame_release_buffer, NULL,
+ AV_BUFFER_FLAG_READONLY);
+ if (!pkt->buf)
+ goto fail;
+
+ pkt->data = pkt->buf->data;
+ pkt->size = sizeof(*data);
+ pkt->flags= AV_PKT_FLAG_KEY | AV_PKT_FLAG_FRAME;
+ pkt->pts = pkt->dts = frame->pts;
+ pkt->pos = av_frame_get_pkt_pos(frame);
+ pkt->duration = av_frame_get_pkt_duration(frame);
+ return 0;
+
+fail:
+ av_frame_free(data);
+ av_freep(&data);
+ return ret;
+}
+
+int av_packet_decode_frame(const AVPacket *pkt, AVFrame *frame)
+{
+ if (!(pkt->flags & AV_PKT_FLAG_FRAME) || pkt->data != pkt->buf->data)
+ return AVERROR(EINVAL);
+
+ return av_frame_ref(frame, *(const AVFrame **) pkt->data);
+}
+
+const AVFrame *av_packet_get_frame(const AVPacket *pkt)
+{
+ if (!(pkt->flags & AV_PKT_FLAG_FRAME) || pkt->data != pkt->buf->data)
+ return NULL;
+
+ return *(const AVFrame **) pkt->data;
+}
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 9cad3e6..1c63a78 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2643,6 +2643,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("Xbox Media Audio 2"),
.props = AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_WRAPPED_AVFRAME_AUDIO,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "wrapped_avframe_audio",
+ .long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
/* subtitle codecs */
{
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 1e21f15..5eecf5b 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
-#define LIBAVCODEC_VERSION_MINOR 15
+#define LIBAVCODEC_VERSION_MINOR 16
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
diff --git a/libavcodec/wrapped_avframe.c b/libavcodec/wrapped_avframe.c
index 13c8d8a..981b4d5 100644
--- a/libavcodec/wrapped_avframe.c
+++ b/libavcodec/wrapped_avframe.c
@@ -29,40 +29,57 @@
#include "libavutil/internal.h"
#include "libavutil/frame.h"
-#include "libavutil/buffer.h"
#include "libavutil/pixdesc.h"
-static void wrapped_avframe_release_buffer(void *unused, uint8_t *data)
+static int is_valid_frame(const AVCodecContext *avctx, const AVFrame *frame)
{
- AVFrame *frame = (AVFrame *)data;
-
- av_frame_free(&frame);
+ if (frame->format < 0)
+ return 0;
+ if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
+ return frame->width > 0 && frame->height > 0;
+ if (avctx->codec_type == AVMEDIA_TYPE_AUDIO)
+ return frame->nb_samples > 0;
+ return 0;
}
static int wrapped_avframe_encode(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *frame, int *got_packet)
{
- AVFrame *wrapped = av_frame_clone(frame);
+ int ret;
- if (!wrapped)
- return AVERROR(ENOMEM);
+ if (!is_valid_frame(avctx, frame))
+ return AVERROR(EINVAL);
- pkt->buf = av_buffer_create((uint8_t *)wrapped, sizeof(*wrapped),
- wrapped_avframe_release_buffer, NULL,
- AV_BUFFER_FLAG_READONLY);
- if (!pkt->buf) {
- av_frame_free(&wrapped);
- return AVERROR(ENOMEM);
+ if (pkt->data) {
+ av_log(avctx, AV_LOG_ERROR, "wrapped_avframe does not support user supplied buffer\n");
+ return AVERROR(EINVAL);
}
- pkt->data = (uint8_t *)wrapped;
- pkt->size = sizeof(*wrapped);
+ if ((ret = av_packet_encode_frame(pkt, frame)) < 0)
+ return ret;
- pkt->flags |= AV_PKT_FLAG_KEY;
*got_packet = 1;
return 0;
}
+static int wrapped_avframe_decode(AVCodecContext *avctx, void *data, int *gotptr,
+ AVPacket *pkt)
+{
+ int ret;
+ AVFrame *out = (AVFrame *) data;
+ const AVFrame *frame = av_packet_get_frame(pkt);
+
+ if (!frame || !is_valid_frame(avctx, frame))
+ return AVERROR(EINVAL);
+
+ if ((ret = av_packet_decode_frame(pkt, out)) < 0)
+ return ret;
+
+ *gotptr = 1;
+
+ return pkt->size;
+}
+
AVCodec ff_wrapped_avframe_encoder = {
.name = "wrapped_avframe",
.long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"),
@@ -71,3 +88,30 @@ AVCodec ff_wrapped_avframe_encoder = {
.encode2 = wrapped_avframe_encode,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
};
+
+AVCodec ff_wrapped_avframe_audio_encoder = {
+ .name = "wrapped_avframe_audio",
+ .long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_WRAPPED_AVFRAME_AUDIO,
+ .encode2 = wrapped_avframe_encode,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
+};
+
+AVCodec ff_wrapped_avframe_decoder = {
+ .name = "wrapped_avframe",
+ .long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"),
+ .type = AVMEDIA_TYPE_VIDEO,
+ .id = AV_CODEC_ID_WRAPPED_AVFRAME,
+ .decode = wrapped_avframe_decode,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
+};
+
+AVCodec ff_wrapped_avframe_audio_decoder = {
+ .name = "wrapped_avframe_audio",
+ .long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"),
+ .type = AVMEDIA_TYPE_AUDIO,
+ .id = AV_CODEC_ID_WRAPPED_AVFRAME_AUDIO,
+ .decode = wrapped_avframe_decode,
+ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
+};
diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c
index 25bf13f..3683f1a 100644
--- a/libavformat/yuv4mpegenc.c
+++ b/libavformat/yuv4mpegenc.c
@@ -138,14 +138,15 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt)
{
AVStream *st = s->streams[pkt->stream_index];
AVIOContext *pb = s->pb;
- AVFrame *frame;
+ const AVFrame *frame;
int* first_pkt = s->priv_data;
int width, height, h_chroma_shift, v_chroma_shift;
int i;
char buf2[Y4M_LINE_MAX + 1];
uint8_t *ptr, *ptr1, *ptr2;
- frame = (AVFrame *)pkt->data;
+ if (!(frame = av_packet_get_frame(pkt)))
+ return AVERROR(EINVAL);
/* for the first packet we have to output the header as well */
if (*first_pkt) {
--
1.8.3.1
More information about the ffmpeg-devel
mailing list