@@ -32,6 +32,7 @@
#include "libavutil/intfloat.h"
#include "libavutil/time_internal.h"
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "wtv.h"
#include "mpegts.h"
@@ -59,6 +60,11 @@ typedef struct WtvFile {
int64_t length;
} WtvFile;
+typedef struct WtvAVIOContext {
+ AVIOContext pb;
+ WtvFile opaque;
+} WtvAVIOContext;
+
static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset)
{
return avio_seek(pb, (sector << WTV_SECTOR_BITS) + offset, SEEK_SET);
@@ -146,35 +152,32 @@ static int read_ints(AVIOContext *pb, uint32_t *data, int count)
* @param first_sector First sector
* @param length Length of file (bytes)
* @param depth File allocation table depth
- * @return NULL on error
+ * @return <0 on error
*/
-static AVIOContext * wtvfile_open_sector(unsigned first_sector, uint64_t length, int depth, AVFormatContext *s)
+static int wtvfile_open_sector(WtvAVIOContext *pb, AVFormatContext *s,
+ unsigned first_sector, uint64_t length, int depth)
{
- AVIOContext *pb;
WtvFile *wf;
uint8_t *buffer;
- int64_t size;
+ int64_t ret, size;
- if (seek_by_sector(s->pb, first_sector, 0) < 0)
- return NULL;
+ if ((ret = seek_by_sector(s->pb, first_sector, 0)) < 0)
+ return ret;
- wf = av_mallocz(sizeof(WtvFile));
- if (!wf)
- return NULL;
+ wf = &pb->opaque;
+ memset(wf, 0, sizeof(*wf));
if (depth == 0) {
wf->sectors = av_malloc(sizeof(uint32_t));
if (!wf->sectors) {
- av_free(wf);
- return NULL;
+ return AVERROR(ENOMEM);
}
wf->sectors[0] = first_sector;
wf->nb_sectors = 1;
} else if (depth == 1) {
wf->sectors = av_malloc(WTV_SECTOR_SIZE);
if (!wf->sectors) {
- av_free(wf);
- return NULL;
+ return AVERROR(ENOMEM);
}
wf->nb_sectors = read_ints(s->pb, wf->sectors, WTV_SECTOR_SIZE / 4);
} else if (depth == 2) {
@@ -184,8 +187,7 @@ static AVIOContext * wtvfile_open_sector(unsigned first_sector, uint64_t length,
wf->sectors = av_malloc_array(nb_sectors1, 1 << WTV_SECTOR_BITS);
if (!wf->sectors) {
- av_free(wf);
- return NULL;
+ return AVERROR(ENOMEM);
}
wf->nb_sectors = 0;
for (i = 0; i < nb_sectors1; i++) {
@@ -195,15 +197,13 @@ static AVIOContext * wtvfile_open_sector(unsigned first_sector, uint64_t length,
}
} else {
av_log(s, AV_LOG_ERROR, "unsupported file allocation table depth (0x%x)\n", depth);
- av_free(wf);
- return NULL;
+ return AVERROR_INVALIDDATA;
}
wf->sector_bits = length & (1ULL<<63) ? WTV_SECTOR_BITS : WTV_BIGSECTOR_BITS;
if (!wf->nb_sectors) {
av_freep(&wf->sectors);
- av_freep(&wf);
- return NULL;
+ return AVERROR_INVALIDDATA;
}
size = avio_size(s->pb);
@@ -220,28 +220,21 @@ static AVIOContext * wtvfile_open_sector(unsigned first_sector, uint64_t length,
/* seek to initial sector */
wf->position = 0;
- if (seek_by_sector(s->pb, wf->sectors[0], 0) < 0) {
+ if ((ret = seek_by_sector(s->pb, wf->sectors[0], 0)) < 0) {
av_freep(&wf->sectors);
- av_freep(&wf);
- return NULL;
+ return ret;
}
wf->pb_filesystem = s->pb;
buffer = av_malloc(1 << wf->sector_bits);
if (!buffer) {
av_freep(&wf->sectors);
- av_freep(&wf);
- return NULL;
+ return AVERROR(ENOMEM);
}
- pb = avio_alloc_context(buffer, 1 << wf->sector_bits, 0, wf,
+ ffio_init_context(&pb->pb, buffer, 1 << wf->sector_bits, 0, wf,
wtvfile_read_packet, NULL, wtvfile_seek);
- if (!pb) {
- av_freep(&buffer);
- av_freep(&wf->sectors);
- av_freep(&wf);
- }
- return pb;
+ return 0;
}
/**
@@ -250,9 +243,10 @@ static AVIOContext * wtvfile_open_sector(unsigned first_sector, uint64_t length,
* @param buf_size directory buffer size
* @param[in] filename
* @param filename_size size of filename
- * @return NULL on error
+ * @return <0 on error
*/
-static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int buf_size, const uint8_t *filename, int filename_size)
+static int wtvfile_open2(WtvAVIOContext *pb, AVFormatContext *s, const uint8_t *buf,
+ int buf_size, const uint8_t *filename, int filename_size)
{
const uint8_t *buf_end = buf + buf_size;
@@ -285,26 +279,23 @@ static AVIOContext * wtvfile_open2(AVFormatContext *s, const uint8_t *buf, int b
if (name_size >= filename_size &&
!memcmp(name, filename, filename_size) &&
(name_size < filename_size + 2 || !AV_RN16(name + filename_size)))
- return wtvfile_open_sector(first_sector, file_length, depth, s);
+ return wtvfile_open_sector(pb, s, first_sector, file_length, depth);
buf += dir_length;
}
- return NULL;
+ return AVERROR_INVALIDDATA;
}
-#define wtvfile_open(s, buf, buf_size, filename) \
- wtvfile_open2(s, buf, buf_size, filename, sizeof(filename))
+#define wtvfile_open(pb, s, buf, buf_size, filename) \
+ wtvfile_open2(pb, s, buf, buf_size, filename, sizeof(filename))
/**
* Close file opened with wtvfile_open_sector(), or wtv_open()
*/
-static void wtvfile_close(AVIOContext *pb)
+static void wtvfile_close(WtvAVIOContext *pb)
{
- WtvFile *wf = pb->opaque;
- av_freep(&wf->sectors);
- av_freep(&pb->opaque);
- av_freep(&pb->buffer);
- avio_context_free(&pb);
+ av_freep(&pb->opaque.sectors);
+ av_freep(&pb->pb.buffer);
}
/*
@@ -316,7 +307,7 @@ typedef struct WtvStream {
} WtvStream;
typedef struct WtvContext {
- AVIOContext *pb; /**< timeline file */
+ WtvAVIOContext pb; /**< timeline file */
int64_t epoch;
int64_t pts; /**< pts for next data chunk */
int64_t last_valid_pts; /**< latest valid pts, used for interactive seeking */
@@ -561,7 +552,7 @@ static void parse_legacy_attrib(AVFormatContext *s, AVIOContext *pb)
static int parse_videoinfoheader2(AVFormatContext *s, AVStream *st)
{
WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
+ AVIOContext *pb = &wtv->pb.pb;
avio_skip(pb, 72); // picture aspect ratio is unreliable
st->codecpar->codec_tag = ff_get_bmp_header(pb, st, NULL);
@@ -640,7 +631,7 @@ static AVStream * parse_media_type(AVFormatContext *s, AVStream *st, int sid,
ff_asf_guid formattype, uint64_t size)
{
WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
+ AVIOContext *pb = &wtv->pb.pb;
if (!ff_guidcmp(subtype, ff_mediasubtype_cpfilters_processed) &&
!ff_guidcmp(formattype, ff_format_cpfilters_processed)) {
ff_asf_guid actual_subtype;
@@ -758,7 +749,7 @@ enum {
*/
static int recover(WtvContext *wtv, uint64_t broken_pos)
{
- AVIOContext *pb = wtv->pb;
+ AVIOContext *pb = &wtv->pb.pb;
int i;
for (i = 0; i < wtv->nb_index_entries; i++) {
if (wtv->index_entries[i].pos > broken_pos) {
@@ -782,7 +773,7 @@ static int recover(WtvContext *wtv, uint64_t broken_pos)
static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_ptr)
{
WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
+ AVIOContext *pb = &wtv->pb.pb;
while (!avio_feof(pb)) {
ff_asf_guid g;
int len, sid, consumed;
@@ -959,7 +950,8 @@ static int read_header(AVFormatContext *s)
unsigned root_sector;
int root_size;
uint8_t root[WTV_SECTOR_SIZE];
- AVIOContext *pb;
+ WtvAVIOContext tmp;
+ AVIOContext *pb = &tmp.pb;
int64_t timeline_pos;
int64_t ret;
@@ -985,26 +977,27 @@ static int read_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
/* parse chunks up until first data chunk */
- wtv->pb = wtvfile_open(s, root, root_size, ff_timeline_le16);
- if (!wtv->pb) {
+ ret = wtvfile_open(&wtv->pb, s, root, root_size, ff_timeline_le16);
+ if (ret < 0) {
av_log(s, AV_LOG_ERROR, "timeline data missing\n");
- return AVERROR_INVALIDDATA;
+ return ret;
}
ret = parse_chunks(s, SEEK_TO_DATA, 0, 0);
if (ret < 0) {
- wtvfile_close(wtv->pb);
+ wtvfile_close(&wtv->pb);
return ret;
}
- avio_seek(wtv->pb, -32, SEEK_CUR);
+ avio_seek(&wtv->pb.pb, -32, SEEK_CUR);
timeline_pos = avio_tell(s->pb); // save before opening another file
/* read metadata */
- pb = wtvfile_open(s, root, root_size, ff_table_0_entries_legacy_attrib_le16);
- if (pb) {
+ ret = wtvfile_open(&tmp, s, root, root_size,
+ ff_table_0_entries_legacy_attrib_le16);
+ if (ret >= 0) {
parse_legacy_attrib(s, pb);
- wtvfile_close(pb);
+ wtvfile_close(&tmp);
}
s->ctx_flags |= AVFMTCTX_NOHEADER; // Needed for noStreams.wtv
@@ -1012,8 +1005,8 @@ static int read_header(AVFormatContext *s)
/* read seek index */
if (s->nb_streams) {
AVStream *st = s->streams[0];
- pb = wtvfile_open(s, root, root_size, ff_table_0_entries_time_le16);
- if (pb) {
+ ret = wtvfile_open(&tmp, s, root, root_size, ff_table_0_entries_time_le16);
+ if (ret >= 0) {
while(1) {
uint64_t timestamp = avio_rl64(pb);
uint64_t frame_nb = avio_rl64(pb);
@@ -1022,11 +1015,11 @@ static int read_header(AVFormatContext *s)
ff_add_index_entry(&wtv->index_entries, &wtv->nb_index_entries, &wtv->index_entries_allocated_size,
0, timestamp, frame_nb, 0, AVINDEX_KEYFRAME);
}
- wtvfile_close(pb);
+ wtvfile_close(&tmp);
if (wtv->nb_index_entries) {
- pb = wtvfile_open(s, root, root_size, ff_timeline_table_0_entries_Events_le16);
- if (pb) {
+ ret = wtvfile_open(&tmp, s, root, root_size, ff_timeline_table_0_entries_Events_le16);
+ if (ret >= 0) {
AVIndexEntry *e = wtv->index_entries;
AVIndexEntry *e_end = wtv->index_entries + wtv->nb_index_entries - 1;
uint64_t last_position = 0;
@@ -1042,7 +1035,7 @@ static int read_header(AVFormatContext *s)
last_position = position;
}
e_end->pos = last_position;
- wtvfile_close(pb);
+ wtvfile_close(&tmp);
st->duration = e_end->timestamp;
}
}
@@ -1056,7 +1049,7 @@ static int read_header(AVFormatContext *s)
static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
+ AVIOContext *pb = &wtv->pb.pb;
int stream_index, len, ret;
stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len);
@@ -1076,7 +1069,7 @@ static int read_seek(AVFormatContext *s, int stream_index,
int64_t ts, int flags)
{
WtvContext *wtv = s->priv_data;
- AVIOContext *pb = wtv->pb;
+ AVIOContext *pb = &wtv->pb.pb;
AVStream *st = s->streams[0];
int64_t ts_relative;
int i;
@@ -1116,7 +1109,7 @@ static int read_close(AVFormatContext *s)
{
WtvContext *wtv = s->priv_data;
av_freep(&wtv->index_entries);
- wtvfile_close(wtv->pb);
+ wtvfile_close(&wtv->pb);
return 0;
}
The WTV demuxer uses a custom AVIOContext internally (complete with own seeking and read_packet-functions). And opening one of these entailed several allocations, including the AVIOContext as well as its opaque. Yet there is no need to allocate these separately on the heap: For those AVIOContexts whose lifetime does not extend beyond reading the header the AVIOContext and the opaque can be put on the stack; whereas the AVIOContext that is kept (and used to read the actual packets) can be made a part of the demuxer's context. By combining the AVIOContext and the opaque into a single structure it is also more clear which AVIOContext is of the custom type and needs to be closed manually (via wtvfile_close()). Furthermore, this commit changes how the AVIOContext is returned: Given that the destination for the AVIOContext is now prescribed by the caller and no longer allocated by wtvfile_open_sector(), it is returned via the same pointer argument and no longer via the ordinary return value; instead an int is returned which makes it possible to return better error codes and to distinguish between allocation failures and other errors. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com> --- libavformat/wtvdec.c | 125 ++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 66 deletions(-)