|
|
|
/*
|
|
|
|
* AVPacket functions for libavcodec
|
|
|
|
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
|
|
|
|
*
|
|
|
|
* 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 <string.h>
|
|
|
|
|
|
|
|
#include "libavutil/avassert.h"
|
|
|
|
#include "libavutil/common.h"
|
|
|
|
#include "libavutil/internal.h"
|
|
|
|
#include "libavutil/mathematics.h"
|
|
|
|
#include "libavutil/mem.h"
|
|
|
|
|
|
|
|
#include "bytestream.h"
|
|
|
|
#include "internal.h"
|
|
|
|
#include "packet.h"
|
|
|
|
#include "packet_internal.h"
|
|
|
|
|
|
|
|
void av_init_packet(AVPacket *pkt)
|
|
|
|
{
|
|
|
|
pkt->pts = AV_NOPTS_VALUE;
|
|
|
|
pkt->dts = AV_NOPTS_VALUE;
|
|
|
|
pkt->pos = -1;
|
|
|
|
pkt->duration = 0;
|
|
|
|
#if FF_API_CONVERGENCE_DURATION
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
pkt->convergence_duration = 0;
|
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
pkt->flags = 0;
|
|
|
|
pkt->stream_index = 0;
|
|
|
|
pkt->buf = NULL;
|
|
|
|
pkt->side_data = NULL;
|
|
|
|
pkt->side_data_elems = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
AVPacket *av_packet_alloc(void)
|
|
|
|
{
|
|
|
|
AVPacket *pkt = av_mallocz(sizeof(AVPacket));
|
|
|
|
if (!pkt)
|
|
|
|
return pkt;
|
|
|
|
|
|
|
|
av_init_packet(pkt);
|
|
|
|
|
|
|
|
return pkt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void av_packet_free(AVPacket **pkt)
|
|
|
|
{
|
|
|
|
if (!pkt || !*pkt)
|
|
|
|
return;
|
|
|
|
|
|
|
|
av_packet_unref(*pkt);
|
|
|
|
av_freep(pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int packet_alloc(AVBufferRef **buf, int size)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
if (size < 0 || size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
|
|
|
|
ret = av_buffer_realloc(buf, size + AV_INPUT_BUFFER_PADDING_SIZE);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
memset((*buf)->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_new_packet(AVPacket *pkt, int size)
|
|
|
|
{
|
|
|
|
AVBufferRef *buf = NULL;
|
|
|
|
int ret = packet_alloc(&buf, size);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
av_init_packet(pkt);
|
|
|
|
pkt->buf = buf;
|
|
|
|
pkt->data = buf->data;
|
|
|
|
pkt->size = size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void av_shrink_packet(AVPacket *pkt, int size)
|
|
|
|
{
|
|
|
|
if (pkt->size <= size)
|
|
|
|
return;
|
|
|
|
pkt->size = size;
|
|
|
|
memset(pkt->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 ((unsigned)grow_by >
|
|
|
|
INT_MAX - (pkt->size + AV_INPUT_BUFFER_PADDING_SIZE))
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
new_size = pkt->size + grow_by + AV_INPUT_BUFFER_PADDING_SIZE;
|
|
|
|
if (pkt->buf) {
|
|
|
|
size_t data_offset;
|
|
|
|
uint8_t *old_data = pkt->data;
|
|
|
|
if (pkt->data == NULL) {
|
|
|
|
data_offset = 0;
|
|
|
|
pkt->data = pkt->buf->data;
|
|
|
|
} else {
|
|
|
|
data_offset = pkt->data - pkt->buf->data;
|
|
|
|
if (data_offset > INT_MAX - new_size)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_size + data_offset > pkt->buf->size ||
|
|
|
|
!av_buffer_is_writable(pkt->buf)) {
|
|
|
|
int ret = av_buffer_realloc(&pkt->buf, new_size + data_offset);
|
|
|
|
if (ret < 0) {
|
|
|
|
pkt->data = old_data;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
pkt->data = pkt->buf->data + data_offset;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pkt->buf = av_buffer_alloc(new_size);
|
|
|
|
if (!pkt->buf)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
if (pkt->size > 0)
|
|
|
|
memcpy(pkt->buf->data, pkt->data, pkt->size);
|
|
|
|
pkt->data = pkt->buf->data;
|
|
|
|
}
|
|
|
|
pkt->size += grow_by;
|
|
|
|
memset(pkt->data + pkt->size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
|
|
|
|
{
|
|
|
|
if (size >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
|
|
|
|
pkt->buf = av_buffer_create(data, size + AV_INPUT_BUFFER_PADDING_SIZE,
|
|
|
|
av_buffer_default_free, NULL, 0);
|
|
|
|
if (!pkt->buf)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
pkt->data = data;
|
|
|
|
pkt->size = size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if FF_API_AVPACKET_OLD_API
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
#define ALLOC_MALLOC(data, size) data = av_malloc(size)
|
|
|
|
#define ALLOC_BUF(data, size) \
|
|
|
|
do { \
|
|
|
|
av_buffer_realloc(&pkt->buf, size); \
|
|
|
|
data = pkt->buf ? pkt->buf->data : NULL; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define DUP_DATA(dst, src, size, padding, ALLOC) \
|
|
|
|
do { \
|
|
|
|
void *data; \
|
|
|
|
if (padding) { \
|
|
|
|
if ((unsigned)(size) > \
|
|
|
|
(unsigned)(size) + AV_INPUT_BUFFER_PADDING_SIZE) \
|
|
|
|
goto failed_alloc; \
|
|
|
|
ALLOC(data, size + AV_INPUT_BUFFER_PADDING_SIZE); \
|
|
|
|
} else { \
|
|
|
|
ALLOC(data, size); \
|
|
|
|
} \
|
|
|
|
if (!data) \
|
|
|
|
goto failed_alloc; \
|
|
|
|
memcpy(data, src, size); \
|
|
|
|
if (padding) \
|
|
|
|
memset((uint8_t *)data + size, 0, \
|
|
|
|
AV_INPUT_BUFFER_PADDING_SIZE); \
|
|
|
|
dst = data; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* Makes duplicates of data, side_data, but does not copy any other fields */
|
|
|
|
static int copy_packet_data(AVPacket *pkt, const AVPacket *src, int dup)
|
|
|
|
{
|
|
|
|
pkt->data = NULL;
|
|
|
|
pkt->side_data = NULL;
|
|
|
|
pkt->side_data_elems = 0;
|
|
|
|
if (pkt->buf) {
|
|
|
|
AVBufferRef *ref = av_buffer_ref(src->buf);
|
|
|
|
if (!ref)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
pkt->buf = ref;
|
|
|
|
pkt->data = ref->data;
|
|
|
|
} else {
|
|
|
|
DUP_DATA(pkt->data, src->data, pkt->size, 1, ALLOC_BUF);
|
|
|
|
}
|
|
|
|
if (src->side_data_elems && dup) {
|
|
|
|
pkt->side_data = src->side_data;
|
|
|
|
pkt->side_data_elems = src->side_data_elems;
|
|
|
|
}
|
|
|
|
if (src->side_data_elems && !dup) {
|
|
|
|
return av_copy_packet_side_data(pkt, src);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
failed_alloc:
|
|
|
|
av_packet_unref(pkt);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_copy_packet_side_data(AVPacket *pkt, const AVPacket *src)
|
|
|
|
{
|
|
|
|
if (src->side_data_elems) {
|
|
|
|
int i;
|
|
|
|
DUP_DATA(pkt->side_data, src->side_data,
|
|
|
|
src->side_data_elems * sizeof(*src->side_data), 0, ALLOC_MALLOC);
|
|
|
|
if (src != pkt) {
|
|
|
|
memset(pkt->side_data, 0,
|
|
|
|
src->side_data_elems * sizeof(*src->side_data));
|
|
|
|
}
|
|
|
|
for (i = 0; i < src->side_data_elems; i++) {
|
|
|
|
DUP_DATA(pkt->side_data[i].data, src->side_data[i].data,
|
|
|
|
src->side_data[i].size, 1, ALLOC_MALLOC);
|
|
|
|
pkt->side_data[i].size = src->side_data[i].size;
|
|
|
|
pkt->side_data[i].type = src->side_data[i].type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pkt->side_data_elems = src->side_data_elems;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
failed_alloc:
|
|
|
|
av_packet_unref(pkt);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_dup_packet(AVPacket *pkt)
|
|
|
|
{
|
|
|
|
AVPacket tmp_pkt;
|
|
|
|
|
|
|
|
if (!pkt->buf && pkt->data) {
|
|
|
|
tmp_pkt = *pkt;
|
|
|
|
return copy_packet_data(pkt, &tmp_pkt, 1);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_copy_packet(AVPacket *dst, const AVPacket *src)
|
|
|
|
{
|
|
|
|
*dst = *src;
|
|
|
|
return copy_packet_data(dst, src, 0);
|
|
|
|
}
|
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void av_packet_free_side_data(AVPacket *pkt)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < pkt->side_data_elems; i++)
|
|
|
|
av_freep(&pkt->side_data[i].data);
|
|
|
|
av_freep(&pkt->side_data);
|
|
|
|
pkt->side_data_elems = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if FF_API_AVPACKET_OLD_API
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
void av_free_packet(AVPacket *pkt)
|
|
|
|
{
|
|
|
|
if (pkt) {
|
|
|
|
if (pkt->buf)
|
|
|
|
av_buffer_unref(&pkt->buf);
|
|
|
|
pkt->data = NULL;
|
|
|
|
pkt->size = 0;
|
|
|
|
|
|
|
|
av_packet_free_side_data(pkt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
|
|
|
|
uint8_t *data, size_t size)
|
|
|
|
{
|
|
|
|
AVPacketSideData *tmp;
|
|
|
|
int i, elems = pkt->side_data_elems;
|
|
|
|
|
|
|
|
for (i = 0; i < elems; i++) {
|
|
|
|
AVPacketSideData *sd = &pkt->side_data[i];
|
|
|
|
|
|
|
|
if (sd->type == type) {
|
|
|
|
av_free(sd->data);
|
|
|
|
sd->data = data;
|
|
|
|
sd->size = size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((unsigned)elems + 1 > AV_PKT_DATA_NB)
|
|
|
|
return AVERROR(ERANGE);
|
|
|
|
|
|
|
|
tmp = av_realloc(pkt->side_data, (elems + 1) * sizeof(*tmp));
|
|
|
|
if (!tmp)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
pkt->side_data = tmp;
|
|
|
|
pkt->side_data[elems].data = data;
|
|
|
|
pkt->side_data[elems].size = size;
|
|
|
|
pkt->side_data[elems].type = type;
|
|
|
|
pkt->side_data_elems++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint8_t *av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
|
|
|
|
buffer_size_t size)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
uint8_t *data;
|
|
|
|
|
|
|
|
#if FF_API_BUFFER_SIZE_T
|
|
|
|
if ((unsigned)size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
|
|
|
|
#else
|
|
|
|
if (size > SIZE_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
|
|
|
|
#endif
|
|
|
|
return NULL;
|
|
|
|
data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
|
|
|
|
if (!data)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ret = av_packet_add_side_data(pkt, type, data, size);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_freep(&data);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type,
|
|
|
|
buffer_size_t *size)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pkt->side_data_elems; i++) {
|
|
|
|
if (pkt->side_data[i].type == type) {
|
|
|
|
if (size)
|
|
|
|
*size = pkt->side_data[i].size;
|
|
|
|
return pkt->side_data[i].data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (size)
|
|
|
|
*size = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *av_packet_side_data_name(enum AVPacketSideDataType type)
|
|
|
|
{
|
|
|
|
switch(type) {
|
|
|
|
case AV_PKT_DATA_PALETTE: return "Palette";
|
|
|
|
case AV_PKT_DATA_NEW_EXTRADATA: return "New Extradata";
|
|
|
|
case AV_PKT_DATA_PARAM_CHANGE: return "Param Change";
|
|
|
|
case AV_PKT_DATA_H263_MB_INFO: return "H263 MB Info";
|
|
|
|
case AV_PKT_DATA_REPLAYGAIN: return "Replay Gain";
|
|
|
|
case AV_PKT_DATA_DISPLAYMATRIX: return "Display Matrix";
|
|
|
|
case AV_PKT_DATA_STEREO3D: return "Stereo 3D";
|
|
|
|
case AV_PKT_DATA_AUDIO_SERVICE_TYPE: return "Audio Service Type";
|
|
|
|
case AV_PKT_DATA_QUALITY_STATS: return "Quality stats";
|
|
|
|
case AV_PKT_DATA_FALLBACK_TRACK: return "Fallback track";
|
|
|
|
case AV_PKT_DATA_CPB_PROPERTIES: return "CPB properties";
|
|
|
|
case AV_PKT_DATA_SKIP_SAMPLES: return "Skip Samples";
|
|
|
|
case AV_PKT_DATA_JP_DUALMONO: return "JP Dual Mono";
|
|
|
|
case AV_PKT_DATA_STRINGS_METADATA: return "Strings Metadata";
|
|
|
|
case AV_PKT_DATA_SUBTITLE_POSITION: return "Subtitle Position";
|
|
|
|
case AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL: return "Matroska BlockAdditional";
|
|
|
|
case AV_PKT_DATA_WEBVTT_IDENTIFIER: return "WebVTT ID";
|
|
|
|
case AV_PKT_DATA_WEBVTT_SETTINGS: return "WebVTT Settings";
|
|
|
|
case AV_PKT_DATA_METADATA_UPDATE: return "Metadata Update";
|
|
|
|
case AV_PKT_DATA_MPEGTS_STREAM_ID: return "MPEGTS Stream ID";
|
|
|
|
case AV_PKT_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata";
|
|
|
|
case AV_PKT_DATA_CONTENT_LIGHT_LEVEL: return "Content light level metadata";
|
|
|
|
case AV_PKT_DATA_SPHERICAL: return "Spherical Mapping";
|
|
|
|
case AV_PKT_DATA_A53_CC: return "A53 Closed Captions";
|
|
|
|
case AV_PKT_DATA_ENCRYPTION_INIT_INFO: return "Encryption initialization data";
|
|
|
|
case AV_PKT_DATA_ENCRYPTION_INFO: return "Encryption info";
|
|
|
|
case AV_PKT_DATA_AFD: return "Active Format Description data";
|
|
|
|
case AV_PKT_DATA_PRFT: return "Producer Reference Time";
|
|
|
|
case AV_PKT_DATA_ICC_PROFILE: return "ICC Profile";
|
|
|
|
case AV_PKT_DATA_DOVI_CONF: return "DOVI configuration record";
|
|
|
|
case AV_PKT_DATA_S12M_TIMECODE: return "SMPTE ST 12-1:2014 timecode";
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
avcodec, avformat: deprecate anything related to side data merging
This patch deprecates anything that has to do with merging/splitting
side data. Automatic side data merging (and splitting), as well as all
API symbols involved in it, are removed completely.
Two FF_API_ defines are dedicated to deprecating API symbols related to
this: FF_API_MERGE_SD_API removes av_packet_split/merge_side_data in
libavcodec, and FF_API_LAVF_KEEPSIDE_FLAG deprecates
AVFMT_FLAG_KEEP_SIDE_DATA in libavformat.
Since it was claimed that changing the default from merging side data to
not doing it is an ABI change, there are two additional FF_API_ defines,
which stop using the side data merging/splitting by default (and remove
any code in avformat/avcodec doing this): FF_API_MERGE_SD in libavcodec,
and FF_API_LAVF_MERGE_SD in libavformat.
It is very much intended that FF_API_MERGE_SD and FF_API_LAVF_MERGE_SD
are quickly defined to 0 in the next ABI bump, while the API symbols are
retained for a longer time for the sake of compatibility.
AVFMT_FLAG_KEEP_SIDE_DATA will (very much intentionally) do nothing for
most of the time it will still be defined. Keep in mind that no code
exists that actually tries to unset this flag for any reason, nor does
such code need to exist. Code setting this flag explicitly will work as
before. Thus it's ok for AVFMT_FLAG_KEEP_SIDE_DATA to do nothing once
side data merging has been removed from libavformat.
In order to avoid that anyone in the future does this incorrectly, here
is a small guide how to update the internal code on bumps:
- next ABI bump (probably soon):
- define FF_API_LAVF_MERGE_SD to 0, and remove all code covered by it
- define FF_API_MERGE_SD to 0, and remove all code covered by it
- next API bump (typically two years in the future or so):
- define FF_API_LAVF_KEEPSIDE_FLAG to 0, and remove all code covered
by it
- define FF_API_MERGE_SD_API to 0, and remove all code covered by it
This forces anyone who actually wants packet side data to temporarily
use deprecated API to get it all. If you ask me, this is batshit fucked
up crazy, but it's how we roll. Making AVFMT_FLAG_KEEP_SIDE_DATA to be
set by default was rejected as an ABI change, so I'm going all the way
to get rid of this once and for all.
Reviewed-by: James Almer <jamrial@gmail.com>
Reviewed-by: Rostislav Pehlivanov <atomnuker@gmail.com>
Reviewed-by: Michael Niedermayer <michael@niedermayer.cc>
8 years ago
|
|
|
#if FF_API_MERGE_SD_API
|
|
|
|
|
|
|
|
#define FF_MERGE_MARKER 0x8c4d9d108e25e9feULL
|
|
|
|
|
|
|
|
int av_packet_merge_side_data(AVPacket *pkt){
|
|
|
|
if(pkt->side_data_elems){
|
|
|
|
AVBufferRef *buf;
|
|
|
|
int i;
|
|
|
|
uint8_t *p;
|
|
|
|
uint64_t size= pkt->size + 8LL + AV_INPUT_BUFFER_PADDING_SIZE;
|
|
|
|
AVPacket old= *pkt;
|
|
|
|
for (i=0; i<old.side_data_elems; i++) {
|
|
|
|
size += old.side_data[i].size + 5LL;
|
|
|
|
}
|
|
|
|
if (size > INT_MAX)
|
|
|
|
return AVERROR(EINVAL);
|
|
|
|
buf = av_buffer_alloc(size);
|
|
|
|
if (!buf)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
pkt->buf = buf;
|
|
|
|
pkt->data = p = buf->data;
|
|
|
|
pkt->size = size - AV_INPUT_BUFFER_PADDING_SIZE;
|
|
|
|
bytestream_put_buffer(&p, old.data, old.size);
|
|
|
|
for (i=old.side_data_elems-1; i>=0; i--) {
|
|
|
|
bytestream_put_buffer(&p, old.side_data[i].data, old.side_data[i].size);
|
|
|
|
bytestream_put_be32(&p, old.side_data[i].size);
|
|
|
|
*p++ = old.side_data[i].type | ((i==old.side_data_elems-1)*128);
|
|
|
|
}
|
|
|
|
bytestream_put_be64(&p, FF_MERGE_MARKER);
|
|
|
|
av_assert0(p-pkt->data == pkt->size);
|
|
|
|
memset(p, 0, AV_INPUT_BUFFER_PADDING_SIZE);
|
|
|
|
av_packet_unref(&old);
|
|
|
|
pkt->side_data_elems = 0;
|
|
|
|
pkt->side_data = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_packet_split_side_data(AVPacket *pkt){
|
|
|
|
if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == FF_MERGE_MARKER){
|
|
|
|
int i;
|
|
|
|
unsigned int size;
|
|
|
|
uint8_t *p;
|
|
|
|
|
|
|
|
p = pkt->data + pkt->size - 8 - 5;
|
|
|
|
for (i=1; ; i++){
|
|
|
|
size = AV_RB32(p);
|
|
|
|
if (size>INT_MAX - 5 || p - pkt->data < size)
|
|
|
|
return 0;
|
|
|
|
if (p[4]&128)
|
|
|
|
break;
|
|
|
|
if (p - pkt->data < size + 5)
|
|
|
|
return 0;
|
|
|
|
p-= size+5;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > AV_PKT_DATA_NB)
|
|
|
|
return AVERROR(ERANGE);
|
|
|
|
|
|
|
|
pkt->side_data = av_malloc_array(i, sizeof(*pkt->side_data));
|
|
|
|
if (!pkt->side_data)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
p= pkt->data + pkt->size - 8 - 5;
|
|
|
|
for (i=0; ; i++){
|
|
|
|
size= AV_RB32(p);
|
|
|
|
av_assert0(size<=INT_MAX - 5 && p - pkt->data >= size);
|
|
|
|
pkt->side_data[i].data = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
|
|
|
|
pkt->side_data[i].size = size;
|
|
|
|
pkt->side_data[i].type = p[4]&127;
|
|
|
|
if (!pkt->side_data[i].data)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
memcpy(pkt->side_data[i].data, p-size, size);
|
|
|
|
pkt->size -= size + 5;
|
|
|
|
if(p[4]&128)
|
|
|
|
break;
|
|
|
|
p-= size+5;
|
|
|
|
}
|
|
|
|
pkt->size -= 8;
|
|
|
|
pkt->side_data_elems = i+1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size)
|
|
|
|
{
|
|
|
|
AVDictionaryEntry *t = NULL;
|
|
|
|
uint8_t *data = NULL;
|
|
|
|
*size = 0;
|
|
|
|
|
|
|
|
if (!dict)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
while ((t = av_dict_get(dict, "", t, AV_DICT_IGNORE_SUFFIX))) {
|
|
|
|
const size_t keylen = strlen(t->key);
|
|
|
|
const size_t valuelen = strlen(t->value);
|
|
|
|
const size_t new_size = *size + keylen + 1 + valuelen + 1;
|
|
|
|
uint8_t *const new_data = av_realloc(data, new_size);
|
|
|
|
|
|
|
|
if (!new_data)
|
|
|
|
goto fail;
|
|
|
|
data = new_data;
|
|
|
|
if (new_size > INT_MAX)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
memcpy(data + *size, t->key, keylen + 1);
|
|
|
|
memcpy(data + *size + keylen + 1, t->value, valuelen + 1);
|
|
|
|
|
|
|
|
*size = new_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
av_freep(&data);
|
|
|
|
*size = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict)
|
|
|
|
{
|
|
|
|
const uint8_t *end;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!dict || !data || !size)
|
|
|
|
return 0;
|
|
|
|
end = data + size;
|
|
|
|
if (size && end[-1])
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
while (data < end) {
|
|
|
|
const uint8_t *key = data;
|
|
|
|
const uint8_t *val = data + strlen(key) + 1;
|
|
|
|
|
|
|
|
if (val >= end || !*key)
|
|
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
|
|
|
|
ret = av_dict_set(dict, key, val, 0);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
data = val + strlen(val) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type,
|
|
|
|
buffer_size_t size)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < pkt->side_data_elems; i++) {
|
|
|
|
if (pkt->side_data[i].type == type) {
|
|
|
|
if (size > pkt->side_data[i].size)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
pkt->side_data[i].size = size;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return AVERROR(ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
dst->pts = src->pts;
|
|
|
|
dst->dts = src->dts;
|
|
|
|
dst->pos = src->pos;
|
|
|
|
dst->duration = src->duration;
|
|
|
|
#if FF_API_CONVERGENCE_DURATION
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
dst->convergence_duration = src->convergence_duration;
|
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
dst->flags = src->flags;
|
|
|
|
dst->stream_index = src->stream_index;
|
|
|
|
|
|
|
|
dst->side_data = NULL;
|
|
|
|
dst->side_data_elems = 0;
|
|
|
|
for (i = 0; i < src->side_data_elems; i++) {
|
|
|
|
enum AVPacketSideDataType type = src->side_data[i].type;
|
|
|
|
buffer_size_t size = src->side_data[i].size;
|
|
|
|
uint8_t *src_data = src->side_data[i].data;
|
|
|
|
uint8_t *dst_data = av_packet_new_side_data(dst, type, size);
|
|
|
|
|
|
|
|
if (!dst_data) {
|
|
|
|
av_packet_free_side_data(dst);
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
}
|
|
|
|
memcpy(dst_data, src_data, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void av_packet_unref(AVPacket *pkt)
|
|
|
|
{
|
|
|
|
av_packet_free_side_data(pkt);
|
|
|
|
av_buffer_unref(&pkt->buf);
|
|
|
|
av_init_packet(pkt);
|
|
|
|
pkt->data = NULL;
|
|
|
|
pkt->size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_packet_ref(AVPacket *dst, const AVPacket *src)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
dst->buf = NULL;
|
|
|
|
|
|
|
|
ret = av_packet_copy_props(dst, src);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (!src->buf) {
|
|
|
|
ret = packet_alloc(&dst->buf, src->size);
|
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
av_assert1(!src->size || src->data);
|
|
|
|
if (src->size)
|
|
|
|
memcpy(dst->buf->data, src->data, src->size);
|
|
|
|
|
|
|
|
dst->data = dst->buf->data;
|
|
|
|
} else {
|
|
|
|
dst->buf = av_buffer_ref(src->buf);
|
|
|
|
if (!dst->buf) {
|
|
|
|
ret = AVERROR(ENOMEM);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
dst->data = src->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
dst->size = src->size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
|
|
av_packet_unref(dst);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
AVPacket *av_packet_clone(const AVPacket *src)
|
|
|
|
{
|
|
|
|
AVPacket *ret = av_packet_alloc();
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (av_packet_ref(ret, src))
|
|
|
|
av_packet_free(&ret);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
|
|
|
|
{
|
|
|
|
*dst = *src;
|
|
|
|
av_init_packet(src);
|
|
|
|
src->data = NULL;
|
|
|
|
src->size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_packet_make_refcounted(AVPacket *pkt)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (pkt->buf)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = packet_alloc(&pkt->buf, pkt->size);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
av_assert1(!pkt->size || pkt->data);
|
|
|
|
if (pkt->size)
|
|
|
|
memcpy(pkt->buf->data, pkt->data, pkt->size);
|
|
|
|
|
|
|
|
pkt->data = pkt->buf->data;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int av_packet_make_writable(AVPacket *pkt)
|
|
|
|
{
|
|
|
|
AVBufferRef *buf = NULL;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (pkt->buf && av_buffer_is_writable(pkt->buf))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = packet_alloc(&buf, pkt->size);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
av_assert1(!pkt->size || pkt->data);
|
|
|
|
if (pkt->size)
|
|
|
|
memcpy(buf->data, pkt->data, pkt->size);
|
|
|
|
|
|
|
|
av_buffer_unref(&pkt->buf);
|
|
|
|
pkt->buf = buf;
|
|
|
|
pkt->data = buf->data;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
|
|
|
|
{
|
|
|
|
if (pkt->pts != AV_NOPTS_VALUE)
|
|
|
|
pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);
|
|
|
|
if (pkt->dts != AV_NOPTS_VALUE)
|
|
|
|
pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
|
|
|
|
if (pkt->duration > 0)
|
|
|
|
pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
|
|
|
|
#if FF_API_CONVERGENCE_DURATION
|
|
|
|
FF_DISABLE_DEPRECATION_WARNINGS
|
|
|
|
if (pkt->convergence_duration > 0)
|
|
|
|
pkt->convergence_duration = av_rescale_q(pkt->convergence_duration, src_tb, dst_tb);
|
|
|
|
FF_ENABLE_DEPRECATION_WARNINGS
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int avpriv_packet_list_put(AVPacketList **packet_buffer,
|
|
|
|
AVPacketList **plast_pktl,
|
|
|
|
AVPacket *pkt,
|
|
|
|
int (*copy)(AVPacket *dst, const AVPacket *src),
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!pktl)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
if (copy) {
|
|
|
|
ret = copy(&pktl->pkt, pkt);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_free(pktl);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = av_packet_make_refcounted(pkt);
|
|
|
|
if (ret < 0) {
|
|
|
|
av_free(pktl);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
av_packet_move_ref(&pktl->pkt, pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*packet_buffer)
|
|
|
|
(*plast_pktl)->next = pktl;
|
|
|
|
else
|
|
|
|
*packet_buffer = pktl;
|
|
|
|
|
|
|
|
/* Add the packet in the buffered packet list. */
|
|
|
|
*plast_pktl = pktl;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int avpriv_packet_list_get(AVPacketList **pkt_buffer,
|
|
|
|
AVPacketList **pkt_buffer_end,
|
|
|
|
AVPacket *pkt)
|
|
|
|
{
|
|
|
|
AVPacketList *pktl;
|
|
|
|
if (!*pkt_buffer)
|
|
|
|
return AVERROR(EAGAIN);
|
|
|
|
pktl = *pkt_buffer;
|
|
|
|
*pkt = pktl->pkt;
|
|
|
|
*pkt_buffer = pktl->next;
|
|
|
|
if (!pktl->next)
|
|
|
|
*pkt_buffer_end = NULL;
|
|
|
|
av_freep(&pktl);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void avpriv_packet_list_free(AVPacketList **pkt_buf, AVPacketList **pkt_buf_end)
|
|
|
|
{
|
|
|
|
AVPacketList *tmp = *pkt_buf;
|
|
|
|
|
|
|
|
while (tmp) {
|
|
|
|
AVPacketList *pktl = tmp;
|
|
|
|
tmp = pktl->next;
|
|
|
|
av_packet_unref(&pktl->pkt);
|
|
|
|
av_freep(&pktl);
|
|
|
|
}
|
|
|
|
*pkt_buf = NULL;
|
|
|
|
*pkt_buf_end = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, int error_count, int pict_type)
|
|
|
|
{
|
|
|
|
uint8_t *side_data;
|
|
|
|
buffer_size_t side_data_size;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, &side_data_size);
|
|
|
|
if (!side_data) {
|
|
|
|
side_data_size = 4+4+8*error_count;
|
|
|
|
side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_QUALITY_STATS,
|
|
|
|
side_data_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!side_data || side_data_size < 4+4+8*error_count)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
AV_WL32(side_data , quality );
|
|
|
|
side_data[4] = pict_type;
|
|
|
|
side_data[5] = error_count;
|
|
|
|
for (i = 0; i<error_count; i++)
|
|
|
|
AV_WL64(side_data+8 + 8*i , error[i]);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ff_side_data_set_prft(AVPacket *pkt, int64_t timestamp)
|
|
|
|
{
|
|
|
|
AVProducerReferenceTime *prft;
|
|
|
|
uint8_t *side_data;
|
|
|
|
buffer_size_t side_data_size;
|
|
|
|
|
|
|
|
side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &side_data_size);
|
|
|
|
if (!side_data) {
|
|
|
|
side_data_size = sizeof(AVProducerReferenceTime);
|
|
|
|
side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_PRFT, side_data_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!side_data || side_data_size < sizeof(AVProducerReferenceTime))
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
prft = (AVProducerReferenceTime *)side_data;
|
|
|
|
prft->wallclock = timestamp;
|
|
|
|
prft->flags = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|