*/
#include "libavutil/attributes.h"
-#include "libavutil/avstring.h"
-#include "libavutil/bswap.h"
#include "libavutil/common.h"
#include "libavutil/dict.h"
#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
-#include "libavutil/opt.h"
#include "libavutil/time_internal.h"
#include "avformat.h"
#include "avio_internal.h"
#include "avlanguage.h"
-#include "id3v2.h"
#include "internal.h"
#include "riff.h"
#include "asf.h"
} GUIDParseTable;
typedef struct ASFPacket {
- AVPacket avpkt;
+ AVPacket *avpkt;
int64_t dts;
uint32_t frame_num; // ASF payloads with the same number are parts of the same frame
int flags;
avio_skip(pb, 4); // flags
len = avio_rl32(pb);
+ if (avio_feof(pb))
+ return AVERROR_INVALIDDATA;
+
if ((ret = avio_get_str16le(pb, len, name,
sizeof(name))) < len)
avio_skip(pb, len - ret);
return 0;
}
-/* MSDN claims that this should be "compatible with the ID3 frame, APIC",
- * but in reality this is only loosely similar */
-static int asf_read_picture(AVFormatContext *s, int len)
-{
- AVPacket pkt = { 0 };
- const CodecMime *mime = ff_id3v2_mime_tags;
- enum AVCodecID id = AV_CODEC_ID_NONE;
- char mimetype[64];
- uint8_t *desc = NULL;
- AVStream *st = NULL;
- int ret, type, picsize, desc_len;
-
- /* type + picsize + mime + desc */
- if (len < 1 + 4 + 2 + 2) {
- av_log(s, AV_LOG_ERROR, "Invalid attached picture size: %d.\n", len);
- return AVERROR_INVALIDDATA;
- }
-
- /* picture type */
- type = avio_r8(s->pb);
- len--;
- if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types) || type < 0) {
- av_log(s, AV_LOG_WARNING, "Unknown attached picture type: %d.\n", type);
- type = 0;
- }
-
- /* picture data size */
- picsize = avio_rl32(s->pb);
- len -= 4;
-
- /* picture MIME type */
- len -= avio_get_str16le(s->pb, len, mimetype, sizeof(mimetype));
- while (mime->id != AV_CODEC_ID_NONE) {
- if (!strncmp(mime->str, mimetype, sizeof(mimetype))) {
- id = mime->id;
- break;
- }
- mime++;
- }
- if (id == AV_CODEC_ID_NONE) {
- av_log(s, AV_LOG_ERROR, "Unknown attached picture mimetype: %s.\n",
- mimetype);
- return 0;
- }
-
- if (picsize >= len) {
- av_log(s, AV_LOG_ERROR, "Invalid attached picture data size: %d >= %d.\n",
- picsize, len);
- return AVERROR_INVALIDDATA;
- }
-
- /* picture description */
- desc_len = (len - picsize) * 2 + 1;
- desc = av_malloc(desc_len);
- if (!desc)
- return AVERROR(ENOMEM);
- len -= avio_get_str16le(s->pb, len - picsize, desc, desc_len);
-
- ret = av_get_packet(s->pb, &pkt, picsize);
- if (ret < 0)
- goto fail;
-
- st = avformat_new_stream(s, NULL);
- if (!st) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
-
- st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
- st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
- st->codecpar->codec_id = id;
- st->attached_pic = pkt;
- st->attached_pic.stream_index = st->index;
- st->attached_pic.flags |= AV_PKT_FLAG_KEY;
-
- if (*desc) {
- if (av_dict_set(&st->metadata, "title", desc, AV_DICT_DONT_STRDUP_VAL) < 0)
- av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
- } else
- av_freep(&desc);
-
- if (av_dict_set(&st->metadata, "comment", ff_id3v2_picture_types[type], 0) < 0)
- av_log(s, AV_LOG_WARNING, "av_dict_set failed.\n");
-
- return 0;
-
-fail:
- av_freep(&desc);
- av_packet_unref(&pkt);
- return ret;
-}
-
-static void get_id3_tag(AVFormatContext *s, int len)
-{
- ID3v2ExtraMeta *id3v2_extra_meta = NULL;
-
- ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, len);
- if (id3v2_extra_meta) {
- ff_id3v2_parse_apic(s, id3v2_extra_meta);
- ff_id3v2_parse_chapters(s, id3v2_extra_meta);
- }
- ff_id3v2_free_extra_meta(&id3v2_extra_meta);
-}
-
static int process_metadata(AVFormatContext *s, const uint8_t *name, uint16_t name_len,
uint16_t val_len, uint16_t type, AVDictionary **met)
{
asf_read_value(s, name, val_len, type, met);
break;
case ASF_BYTE_ARRAY:
- if (!strcmp(name, "WM/Picture")) // handle cover art
- asf_read_picture(s, val_len);
- else if (!strcmp(name, "ID3")) // handle ID3 tag
- get_id3_tag(s, val_len);
- else
+ if (ff_asf_handle_byte_array(s, name, val_len) > 0)
asf_read_value(s, name, val_len, type, met);
break;
case ASF_GUID:
} else {
if (st_num < ASF_MAX_STREAMS) {
if ((ret = process_metadata(s, name, name_len, val_len, type,
- &asf->asf_sd[st_num].asf_met)) < 0) {
+ st_num ? &asf->asf_sd[st_num].asf_met
+ : &s->metadata)) < 0) {
av_freep(&name);
break;
}
return 0;
}
-static int parse_video_info(AVIOContext *pb, AVStream *st)
+static int parse_video_info(AVFormatContext *avfmt, AVIOContext *pb, AVStream *st)
{
uint16_t size_asf; // ASF-specific Format Data size
uint32_t size_bmp; // BMP_HEADER-specific Format Data size
st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag);
size_bmp = FFMAX(size_asf, size_bmp);
- if (size_bmp > BMP_HEADER_SIZE &&
- size_bmp < INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) {
- int ret;
- st->codecpar->extradata_size = size_bmp - BMP_HEADER_SIZE;
- if (!(st->codecpar->extradata = av_malloc(st->codecpar->extradata_size +
- AV_INPUT_BUFFER_PADDING_SIZE))) {
- st->codecpar->extradata_size = 0;
- return AVERROR(ENOMEM);
- }
- memset(st->codecpar->extradata + st->codecpar->extradata_size , 0,
- AV_INPUT_BUFFER_PADDING_SIZE);
- if ((ret = avio_read(pb, st->codecpar->extradata,
- st->codecpar->extradata_size)) < 0)
+ if (size_bmp > BMP_HEADER_SIZE) {
+ int ret = ff_get_extradata(avfmt, st->codecpar, pb, size_bmp - BMP_HEADER_SIZE);
+
+ if (ret < 0)
return ret;
}
return 0;
asf_st->index = st->index;
asf_st->indexed = 0;
st->id = flags & ASF_STREAM_NUM;
- av_init_packet(&asf_st->pkt.avpkt);
asf_st->pkt.data_size = 0;
+ asf_st->pkt.avpkt = av_packet_alloc();
+ if (!asf_st->pkt.avpkt)
+ return AVERROR(ENOMEM);
avio_skip(pb, 4); // skip reserved field
switch (type) {
break;
case AVMEDIA_TYPE_VIDEO:
asf_st->type = AVMEDIA_TYPE_VIDEO;
- if ((ret = parse_video_info(pb, st)) < 0)
+ if ((ret = parse_video_info(s, pb, st)) < 0)
return ret;
break;
default:
st_num = avio_rl16(pb);
st_num &= ASF_STREAM_NUM;
lang_idx = avio_rl16(pb); // Stream Language ID Index
+ if (lang_idx >= ASF_MAX_STREAMS)
+ return AVERROR_INVALIDDATA;
for (i = 0; i < asf->nb_streams; i++) {
if (st_num == asf->asf_st[i]->stream_index) {
st = s->streams[asf->asf_st[i]->index];
asf_pkt->duration = 0;
asf_pkt->flags = 0;
asf_pkt->dts = 0;
- asf_pkt->duration = 0;
- av_packet_unref(&asf_pkt->avpkt);
- av_init_packet(&asf_pkt->avpkt);
+ av_packet_unref(asf_pkt->avpkt);
}
static int asf_read_replicated_data(AVFormatContext *s, ASFPacket *asf_pkt)
data_size = avio_rl32(pb); // read media object size
if (data_size <= 0)
return AVERROR_INVALIDDATA;
- if ((ret = av_new_packet(&asf_pkt->avpkt, data_size)) < 0)
+ if ((ret = av_new_packet(asf_pkt->avpkt, data_size)) < 0)
return ret;
asf_pkt->data_size = asf_pkt->size_left = data_size;
} else
pay_len, asf->packet_size, avio_tell(pb));
return AVERROR_INVALIDDATA;
}
- p = asf_pkt->avpkt.data + asf_pkt->data_size - asf_pkt->size_left;
+ p = asf_pkt->avpkt->data + asf_pkt->data_size - asf_pkt->size_left;
if (pay_len > asf_pkt->size_left) {
av_log(s, AV_LOG_ERROR,
"Error: invalid buffer size, pay_len %d, data size left %d.\n",
data_size = avio_rl32(pb); // read media object size
if (data_size <= 0)
return AVERROR_EOF;
- if ((ret = av_new_packet(&asf_pkt->avpkt, data_size)) < 0)
+ if ((ret = av_new_packet(asf_pkt->avpkt, data_size)) < 0)
return ret;
asf_pkt->data_size = asf_pkt->size_left = data_size;
} else
avio_tell(pb));
return AVERROR_INVALIDDATA;
}
- p = asf_pkt->avpkt.data + asf_pkt->data_size - asf_pkt->size_left;
+ p = asf_pkt->avpkt->data + asf_pkt->data_size - asf_pkt->size_left;
if (size > asf_pkt->size_left || asf_pkt->size_left <= 0)
return AVERROR_INVALIDDATA;
if (asf_pkt->size_left > size)
{
ASFContext *asf = s->priv_data;
ASFStream *asf_st = asf->asf_st[st_num];
- unsigned char *p = asf_pkt->avpkt.data;
+ unsigned char *p = asf_pkt->avpkt->data;
uint16_t pkt_len = asf->asf_st[st_num]->virtual_pkt_len;
uint16_t chunk_len = asf->asf_st[st_num]->virtual_chunk_len;
int nchunks = pkt_len / chunk_len;
- AVPacket pkt;
+ uint8_t *data;
int pos = 0, j, l, ret;
- if ((ret = av_new_packet(&pkt, asf_pkt->data_size)) < 0)
- return ret;
+ data = av_malloc(asf_pkt->data_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!data)
+ return AVERROR(ENOMEM);
+ memset(data + asf_pkt->data_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
while (asf_pkt->data_size >= asf_st->span * pkt_len + pos) {
if (pos >= asf_pkt->data_size) {
for (j = 0; j < asf_st->span; j++) {
if ((pos + chunk_len) >= asf_pkt->data_size)
break;
- memcpy(pkt.data + pos,
+ memcpy(data + pos,
p + (j * nchunks + l) * chunk_len,
chunk_len);
pos += chunk_len;
}
}
p += asf_st->span * pkt_len;
- if (p > asf_pkt->avpkt.data + asf_pkt->data_size)
+ if (p > asf_pkt->avpkt->data + asf_pkt->data_size)
break;
}
- av_packet_unref(&asf_pkt->avpkt);
- asf_pkt->avpkt = pkt;
+ av_packet_unref(asf_pkt->avpkt);
+ ret = av_packet_from_data(asf_pkt->avpkt, data, asf_pkt->data_size);
+ if (ret < 0)
+ av_free(data);
- return 0;
+ return ret;
}
static int asf_read_packet(AVFormatContext *s, AVPacket *pkt)
asf->asf_st[i]->type == AVMEDIA_TYPE_AUDIO)
if ((ret = asf_deinterleave(s, asf_pkt, i)) < 0)
return ret;
- av_packet_move_ref(pkt, &asf_pkt->avpkt);
+ av_packet_move_ref(pkt, asf_pkt->avpkt);
pkt->stream_index = asf->asf_st[i]->index;
pkt->flags = asf_pkt->flags;
pkt->dts = asf_pkt->dts - asf->preroll;
for (i = 0; i < ASF_MAX_STREAMS; i++) {
av_dict_free(&asf->asf_sd[i].asf_met);
if (i < asf->nb_streams) {
- av_packet_unref(&asf->asf_st[i]->pkt.avpkt);
+ av_packet_free(&asf->asf_st[i]->pkt.avpkt);
av_freep(&asf->asf_st[i]);
}
}
asf->sub_dts = 0;
for (i = 0; i < asf->nb_streams; i++) {
ASFPacket *pkt = &asf->asf_st[i]->pkt;
- pkt->size_left = 0;
- pkt->data_size = 0;
- pkt->duration = 0;
- pkt->flags = 0;
- pkt->dts = 0;
- pkt->duration = 0;
- av_packet_unref(&pkt->avpkt);
- av_init_packet(&pkt->avpkt);
+ reset_packet(pkt);
}
}
{
ASFContext *asf = s->priv_data;
int64_t pkt_pos = *pos, pkt_offset, dts = AV_NOPTS_VALUE, data_end;
- AVPacket pkt;
+ AVPacket *pkt = av_packet_alloc();
int n;
+ if (!pkt)
+ return AVERROR(ENOMEM);
+
data_end = asf->data_offset + asf->data_size;
n = (pkt_pos - asf->first_packet_offset + asf->packet_size - 1) /
int i, ret, st_found;
- av_init_packet(&pkt);
pkt_offset = avio_tell(s->pb);
- if ((ret = asf_read_packet(s, &pkt)) < 0) {
+ if ((ret = asf_read_packet(s, pkt)) < 0) {
+ av_packet_free(&pkt);
dts = AV_NOPTS_VALUE;
return ret;
}
ASFStream *st = asf->asf_st[i];
st_found = 0;
- if (pkt.flags & AV_PKT_FLAG_KEY) {
- dts = pkt.dts;
+ if (pkt->flags & AV_PKT_FLAG_KEY) {
+ dts = pkt->dts;
if (dts) {
- av_add_index_entry(s->streams[pkt.stream_index], pkt_pos,
- dts, pkt.size, 0, AVINDEX_KEYFRAME);
+ av_add_index_entry(s->streams[pkt->stream_index], pkt_pos,
+ dts, pkt->size, 0, AVINDEX_KEYFRAME);
if (stream_index == st->index) {
st_found = 1;
break;
}
if (st_found)
break;
- av_packet_unref(&pkt);
+ av_packet_unref(pkt);
}
*pos = pkt_pos;
- av_packet_unref(&pkt);
+ av_packet_free(&pkt);
return dts;
}
ff_asf_guid guid;
int ret;
+ if (offset > INT64_MAX - size)
+ return AVERROR_INVALIDDATA;
+
while (avio_tell(pb) <= offset + size) {
if (avio_tell(pb) == asf->offset)
break;