summaryrefslogtreecommitdiff
path: root/libavformat
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/asfdec.c26
-rw-r--r--libavformat/avformat.h16
-rw-r--r--libavformat/dxa.c2
-rw-r--r--libavformat/ffmdec.c2
-rw-r--r--libavformat/ffmenc.c2
-rw-r--r--libavformat/id3v2.c153
-rw-r--r--libavformat/id3v2.h57
-rw-r--r--libavformat/id3v2enc.c192
-rw-r--r--libavformat/internal.h5
-rw-r--r--libavformat/matroska.h6
-rw-r--r--libavformat/mov.c7
-rw-r--r--libavformat/mp3enc.c257
-rw-r--r--libavformat/omadec.c2
-rw-r--r--libavformat/omaenc.c2
-rw-r--r--libavformat/psxstr.c1
-rw-r--r--libavformat/rtpenc.c2
-rw-r--r--libavformat/swfdec.c2
-rw-r--r--libavformat/utils.c55
-rw-r--r--libavformat/version.h2
-rw-r--r--libavformat/vqf.c6
20 files changed, 601 insertions, 196 deletions
diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c
index b37cbb04d3..cdec63b481 100644
--- a/libavformat/asfdec.c
+++ b/libavformat/asfdec.c
@@ -26,7 +26,6 @@
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
-#include "libavcodec/mpegaudio.h"
#include "avformat.h"
#include "internal.h"
#include "avio_internal.h"
@@ -199,6 +198,8 @@ static int asf_read_file_properties(AVFormatContext *s, int64_t size)
asf->hdr.flags = avio_rl32(pb);
asf->hdr.min_pktsize = avio_rl32(pb);
asf->hdr.max_pktsize = avio_rl32(pb);
+ if (asf->hdr.min_pktsize >= (1U<<29))
+ return AVERROR_INVALIDDATA;
asf->hdr.max_bitrate = avio_rl32(pb);
s->packet_size = asf->hdr.max_pktsize;
@@ -317,25 +318,6 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size)
|| asf_st->ds_packet_size % asf_st->ds_chunk_size)
asf_st->ds_span = 0; // disable descrambling
}
- switch (st->codec->codec_id) {
- case CODEC_ID_MP3:
- st->codec->frame_size = MPA_FRAME_SIZE;
- break;
- case CODEC_ID_PCM_S16LE:
- case CODEC_ID_PCM_S16BE:
- case CODEC_ID_PCM_U16LE:
- case CODEC_ID_PCM_U16BE:
- case CODEC_ID_PCM_S8:
- case CODEC_ID_PCM_U8:
- case CODEC_ID_PCM_ALAW:
- case CODEC_ID_PCM_MULAW:
- st->codec->frame_size = 1;
- break;
- default:
- /* This is probably wrong, but it prevents a crash later */
- st->codec->frame_size = 1;
- break;
- }
} else if (type == AVMEDIA_TYPE_VIDEO &&
size - (avio_tell(pb) - pos1 + 24) >= 51) {
avio_rl32(pb);
@@ -612,7 +594,9 @@ static int asf_read_header(AVFormatContext *s)
if (gsize < 24)
return -1;
if (!ff_guidcmp(&g, &ff_asf_file_header)) {
- asf_read_file_properties(s, gsize);
+ int ret = asf_read_file_properties(s, gsize);
+ if (ret < 0)
+ return ret;
} else if (!ff_guidcmp(&g, &ff_asf_stream_header)) {
asf_read_stream_properties(s, gsize);
} else if (!ff_guidcmp(&g, &ff_asf_comment_header)) {
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 00a52e5da6..1dc74fc9ff 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -541,6 +541,13 @@ typedef struct AVIndexEntry {
#define AV_DISPOSITION_HEARING_IMPAIRED 0x0080 /**< stream for hearing impaired audiences */
#define AV_DISPOSITION_VISUAL_IMPAIRED 0x0100 /**< stream for visual impaired audiences */
#define AV_DISPOSITION_CLEAN_EFFECTS 0x0200 /**< stream without voice */
+/**
+ * The stream is stored in the file as an attached picture/"cover art" (e.g.
+ * APIC frame in ID3v2). The single packet associated with it will be returned
+ * among the first few packets read from the file unless seeking takes place.
+ * It can also be accessed at any time in AVStream.attached_pic.
+ */
+#define AV_DISPOSITION_ATTACHED_PIC 0x0400
/**
* Stream structure.
@@ -615,6 +622,15 @@ typedef struct AVStream {
*/
AVRational avg_frame_rate;
+ /**
+ * For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet
+ * will contain the attached picture.
+ *
+ * decoding: set by libavformat, must not be modified by the caller.
+ * encoding: unused
+ */
+ AVPacket attached_pic;
+
/*****************************************************************
* All fields below this line are not part of the public API. They
* may not be used outside of libavformat and can be changed and
diff --git a/libavformat/dxa.c b/libavformat/dxa.c
index f4e13835b2..3d85193279 100644
--- a/libavformat/dxa.c
+++ b/libavformat/dxa.c
@@ -107,6 +107,8 @@ static int dxa_read_header(AVFormatContext *s)
ret = ff_get_wav_header(pb, ast->codec, fsize);
if (ret < 0)
return ret;
+ if (ast->codec->sample_rate > 0)
+ avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate);
// find 'data' chunk
while(avio_tell(pb) < c->vidpos && !url_feof(pb)){
tag = avio_rl32(pb);
diff --git a/libavformat/ffmdec.c b/libavformat/ffmdec.c
index f500511d44..6bcb98c72e 100644
--- a/libavformat/ffmdec.c
+++ b/libavformat/ffmdec.c
@@ -338,8 +338,6 @@ static int ffm_read_header(AVFormatContext *s)
codec->dct_algo = avio_rb32(pb);
codec->strict_std_compliance = avio_rb32(pb);
codec->max_b_frames = avio_rb32(pb);
- codec->luma_elim_threshold = avio_rb32(pb);
- codec->chroma_elim_threshold = avio_rb32(pb);
codec->mpeg_quant = avio_rb32(pb);
codec->intra_dc_precision = avio_rb32(pb);
codec->me_method = avio_rb32(pb);
diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c
index eb21fd79bb..84ed697dd5 100644
--- a/libavformat/ffmenc.c
+++ b/libavformat/ffmenc.c
@@ -144,8 +144,6 @@ static int ffm_write_header(AVFormatContext *s)
avio_wb32(pb, codec->dct_algo);
avio_wb32(pb, codec->strict_std_compliance);
avio_wb32(pb, codec->max_b_frames);
- avio_wb32(pb, codec->luma_elim_threshold);
- avio_wb32(pb, codec->chroma_elim_threshold);
avio_wb32(pb, codec->mpeg_quant);
avio_wb32(pb, codec->intra_dc_precision);
avio_wb32(pb, codec->me_method);
diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
index 250281c357..f14b13e92f 100644
--- a/libavformat/id3v2.c
+++ b/libavformat/id3v2.c
@@ -38,6 +38,7 @@
#include "libavutil/intreadwrite.h"
#include "libavutil/dict.h"
#include "avio_internal.h"
+#include "internal.h"
const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
{ "TALB", "album"},
@@ -99,6 +100,38 @@ const char ff_id3v2_3_tags[][4] = {
{ 0 },
};
+const char *ff_id3v2_picture_types[21] = {
+ "Other",
+ "32x32 pixels 'file icon'",
+ "Other file icon",
+ "Cover (front)",
+ "Cover (back)",
+ "Leaflet page",
+ "Media (e.g. label side of CD)",
+ "Lead artist/lead performer/soloist",
+ "Artist/performer",
+ "Conductor",
+ "Band/Orchestra",
+ "Composer",
+ "Lyricist/text writer",
+ "Recording Location",
+ "During recording",
+ "During performance",
+ "Movie/video screen capture",
+ "A bright coloured fish",
+ "Illustration",
+ "Band/artist logotype",
+ "Publisher/Studio logotype",
+};
+
+const CodecMime ff_id3v2_mime_tags[] = {
+ {"image/gif" , CODEC_ID_GIF},
+ {"image/jpeg", CODEC_ID_MJPEG},
+ {"image/png" , CODEC_ID_PNG},
+ {"image/tiff", CODEC_ID_TIFF},
+ {"", CODEC_ID_NONE},
+};
+
int ff_id3v2_match(const uint8_t *buf, const char * magic)
{
return buf[0] == magic[0] &&
@@ -394,6 +427,84 @@ finish:
av_dict_set(m, "date", date, 0);
}
+static void free_apic(void *obj)
+{
+ ID3v2ExtraMetaAPIC *apic = obj;
+ av_freep(&apic->data);
+ av_freep(&apic->description);
+ av_freep(&apic);
+}
+
+static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
+{
+ int enc, pic_type;
+ char mimetype[64];
+ const CodecMime *mime = ff_id3v2_mime_tags;
+ enum CodecID id = CODEC_ID_NONE;
+ ID3v2ExtraMetaAPIC *apic = NULL;
+ ID3v2ExtraMeta *new_extra = NULL;
+ int64_t end = avio_tell(pb) + taglen;
+
+ if (taglen <= 4)
+ goto fail;
+
+ new_extra = av_mallocz(sizeof(*new_extra));
+ apic = av_mallocz(sizeof(*apic));
+ if (!new_extra || !apic)
+ goto fail;
+
+ enc = avio_r8(pb);
+ taglen--;
+
+ /* mimetype */
+ taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
+ while (mime->id != CODEC_ID_NONE) {
+ if (!strncmp(mime->str, mimetype, sizeof(mimetype))) {
+ id = mime->id;
+ break;
+ }
+ mime++;
+ }
+ if (id == CODEC_ID_NONE) {
+ av_log(s, AV_LOG_WARNING, "Unknown attached picture mimetype: %s, skipping.\n", mimetype);
+ goto fail;
+ }
+ apic->id = id;
+
+ /* picture type */
+ pic_type = avio_r8(pb);
+ taglen--;
+ if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) {
+ av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n", pic_type);
+ pic_type = 0;
+ }
+ apic->type = ff_id3v2_picture_types[pic_type];
+
+ /* description and picture data */
+ if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) {
+ av_log(s, AV_LOG_ERROR, "Error decoding attached picture description.\n");
+ goto fail;
+ }
+
+ apic->len = taglen;
+ apic->data = av_malloc(taglen);
+ if (!apic->data || avio_read(pb, apic->data, taglen) != taglen)
+ goto fail;
+
+ new_extra->tag = "APIC";
+ new_extra->data = apic;
+ new_extra->next = *extra_meta;
+ *extra_meta = new_extra;
+
+ return;
+
+fail:
+ if (apic)
+ free_apic(apic);
+ av_freep(&new_extra);
+ avio_seek(pb, end, SEEK_SET);
+}
+
typedef struct ID3v2EMFunc {
const char *tag3;
const char *tag4;
@@ -403,6 +514,7 @@ typedef struct ID3v2EMFunc {
static const ID3v2EMFunc id3v2_extra_meta_funcs[] = {
{ "GEO", "GEOB", read_geobtag, free_geobtag },
+ { "PIC", "APIC", read_apic, free_apic },
{ NULL }
};
@@ -620,7 +732,7 @@ seek:
return;
}
-void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta)
+void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta)
{
int len, ret;
uint8_t buf[ID3v2_HEADER_SIZE];
@@ -651,11 +763,6 @@ void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **e
merge_date(&s->metadata);
}
-void ff_id3v2_read(AVFormatContext *s, const char *magic)
-{
- ff_id3v2_read_all(s, magic, NULL);
-}
-
void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
{
ID3v2ExtraMeta *current = *extra_meta, *next;
@@ -669,3 +776,37 @@ void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
current = next;
}
}
+
+int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta)
+{
+ ID3v2ExtraMeta *cur;
+
+ for (cur = *extra_meta; cur; cur = cur->next) {
+ ID3v2ExtraMetaAPIC *apic;
+ AVStream *st;
+
+ if (strcmp(cur->tag, "APIC"))
+ continue;
+ apic = cur->data;
+
+ if (!(st = avformat_new_stream(s, NULL)))
+ return AVERROR(ENOMEM);
+
+ st->disposition |= AV_DISPOSITION_ATTACHED_PIC;
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ st->codec->codec_id = apic->id;
+ av_dict_set(&st->metadata, "title", apic->description, 0);
+ av_dict_set(&st->metadata, "comment", apic->type, 0);
+
+ av_init_packet(&st->attached_pic);
+ st->attached_pic.data = apic->data;
+ st->attached_pic.size = apic->len;
+ st->attached_pic.destruct = av_destruct_packet;
+ st->attached_pic.stream_index = st->index;
+
+ apic->data = NULL;
+ apic->len = 0;
+ }
+
+ return 0;
+}
diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h
index ebd4a67a33..5c12a47b32 100644
--- a/libavformat/id3v2.h
+++ b/libavformat/id3v2.h
@@ -24,6 +24,7 @@
#include <stdint.h>
#include "avformat.h"
+#include "internal.h"
#include "metadata.h"
#define ID3v2_HEADER_SIZE 10
@@ -45,6 +46,12 @@ enum ID3v2Encoding {
ID3v2_ENCODING_UTF8 = 3,
};
+typedef struct ID3v2EncContext {
+ int version; ///< ID3v2 minor version, either 3 or 4
+ int64_t size_pos; ///< offset of the tag total size
+ int len; ///< size of the tag written so far
+} ID3v2EncContext;
+
typedef struct ID3v2ExtraMeta {
const char *tag;
void *data;
@@ -59,6 +66,14 @@ typedef struct ID3v2ExtraMetaGEOB {
uint8_t *data;
} ID3v2ExtraMetaGEOB;
+typedef struct ID3v2ExtraMetaAPIC {
+ uint8_t *data;
+ int len;
+ const char *type;
+ uint8_t *description;
+ enum CodecID id;
+} ID3v2ExtraMetaAPIC;
+
/**
* Detect ID3v2 Header.
* @param buf must be ID3v2_HEADER_SIZE byte long
@@ -75,24 +90,40 @@ int ff_id3v2_match(const uint8_t *buf, const char *magic);
int ff_id3v2_tag_len(const uint8_t *buf);
/**
- * Read an ID3v2 tag (text tags only)
+ * Read an ID3v2 tag, including supported extra metadata
+ * @param extra_meta If not NULL, extra metadata is parsed into a list of
+ * ID3v2ExtraMeta structs and *extra_meta points to the head of the list
*/
-void ff_id3v2_read(AVFormatContext *s, const char *magic);
+void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta);
/**
- * Read an ID3v2 tag, including supported extra metadata (currently only GEOB)
- * @param extra_meta If not NULL, extra metadata is parsed into a list of
- * ID3v2ExtraMeta structs and *extra_meta points to the head of the list
+ * Initialize an ID3v2 tag.
+ */
+void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version,
+ const char *magic);
+
+/**
+ * Convert and write all global metadata from s into an ID3v2 tag.
+ */
+int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3);
+
+/**
+ * Write an attached picture from pkt into an ID3v2 tag.
+ */
+int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt);
+
+/**
+ * Finalize an opened ID3v2 tag.
*/
-void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta);
+void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb);
/**
- * Write an ID3v2 tag.
+ * Write an ID3v2 tag containing all global metadata from s.
* @param id3v2_version Subversion of ID3v2; supported values are 3 and 4
* @param magic magic bytes to identify the header
* If in doubt, use ID3v2_DEFAULT_MAGIC.
*/
-int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, const char *magic);
+int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version, const char *magic);
/**
* Free memory allocated parsing special (non-text) metadata.
@@ -100,6 +131,12 @@ int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, const char *mag
*/
void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta);
+/**
+ * Create a stream for each APIC (attached picture) extracted from the
+ * ID3v2 header.
+ */
+int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta);
+
extern const AVMetadataConv ff_id3v2_34_metadata_conv[];
extern const AVMetadataConv ff_id3v2_4_metadata_conv[];
@@ -120,4 +157,8 @@ extern const char ff_id3v2_4_tags[][4];
*/
extern const char ff_id3v2_3_tags[][4];
+extern const CodecMime ff_id3v2_mime_tags[];
+
+extern const char *ff_id3v2_picture_types[21];
+
#endif /* AVFORMAT_ID3V2_H */
diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c
index c3732e4789..1caadd6335 100644
--- a/libavformat/id3v2enc.c
+++ b/libavformat/id3v2enc.c
@@ -19,6 +19,8 @@
*/
#include <stdint.h>
+#include <string.h>
+
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
#include "libavutil/intreadwrite.h"
@@ -26,12 +28,12 @@
#include "avio.h"
#include "id3v2.h"
-static void id3v2_put_size(AVFormatContext *s, int size)
+static void id3v2_put_size(AVIOContext *pb, int size)
{
- avio_w8(s->pb, size >> 21 & 0x7f);
- avio_w8(s->pb, size >> 14 & 0x7f);
- avio_w8(s->pb, size >> 7 & 0x7f);
- avio_w8(s->pb, size & 0x7f);
+ avio_w8(pb, size >> 21 & 0x7f);
+ avio_w8(pb, size >> 14 & 0x7f);
+ avio_w8(pb, size >> 7 & 0x7f);
+ avio_w8(pb, size & 0x7f);
}
static int string_is_ascii(const uint8_t *str)
@@ -40,17 +42,30 @@ static int string_is_ascii(const uint8_t *str)
return !*str;
}
+static void id3v2_encode_string(AVIOContext *pb, const uint8_t *str,
+ enum ID3v2Encoding enc)
+{
+ int (*put)(AVIOContext*, const char*);
+
+ if (enc == ID3v2_ENCODING_UTF16BOM) {
+ avio_wl16(pb, 0xFEFF); /* BOM */
+ put = avio_put_str16le;
+ } else
+ put = avio_put_str;
+
+ put(pb, str);
+}
+
/**
* Write a text frame with one (normal frames) or two (TXXX frames) strings
* according to encoding (only UTF-8 or UTF-16+BOM supported).
* @return number of bytes written or a negative error code.
*/
-static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2,
+static int id3v2_put_ttag(ID3v2EncContext *id3, AVIOContext *avioc, const char *str1, const char *str2,
uint32_t tag, enum ID3v2Encoding enc)
{
int len;
uint8_t *pb;
- int (*put)(AVIOContext*, const char*);
AVIOContext *dyn_buf;
if (avio_open_dyn_buf(&dyn_buf) < 0)
return AVERROR(ENOMEM);
@@ -62,28 +77,26 @@ static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2
enc = ID3v2_ENCODING_ISO8859;
avio_w8(dyn_buf, enc);
- if (enc == ID3v2_ENCODING_UTF16BOM) {
- avio_wl16(dyn_buf, 0xFEFF); /* BOM */
- put = avio_put_str16le;
- } else
- put = avio_put_str;
-
- put(dyn_buf, str1);
+ id3v2_encode_string(dyn_buf, str1, enc);
if (str2)
- put(dyn_buf, str2);
+ id3v2_encode_string(dyn_buf, str2, enc);
len = avio_close_dyn_buf(dyn_buf, &pb);
- avio_wb32(s->pb, tag);
- id3v2_put_size(s, len);
- avio_wb16(s->pb, 0);
- avio_write(s->pb, pb, len);
+ avio_wb32(avioc, tag);
+ /* ID3v2.3 frame size is not synchsafe */
+ if (id3->version == 3)
+ avio_wb32(avioc, len);
+ else
+ id3v2_put_size(avioc, len);
+ avio_wb16(avioc, 0);
+ avio_write(avioc, pb, len);
av_freep(&pb);
return len + ID3v2_HEADER_SIZE;
}
-static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const char table[][4],
- enum ID3v2Encoding enc)
+static int id3v2_check_write_tag(ID3v2EncContext *id3, AVIOContext *pb, AVDictionaryEntry *t,
+ const char table[][4], enum ID3v2Encoding enc)
{
uint32_t tag;
int i;
@@ -93,7 +106,7 @@ static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const
tag = AV_RB32(t->key);
for (i = 0; *table[i]; i++)
if (tag == AV_RB32(table[i]))
- return id3v2_put_ttag(s, t->value, NULL, tag, enc);
+ return id3v2_put_ttag(id3, pb, t->value, NULL, tag, enc);
return -1;
}
@@ -135,52 +148,137 @@ static void id3v2_3_metadata_split_date(AVDictionary **pm)
*pm = dst;
}
-int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version,
- const char *magic)
+void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version,
+ const char *magic)
{
- int64_t size_pos, cur_pos;
- AVDictionaryEntry *t = NULL;
+ id3->version = id3v2_version;
- int totlen = 0, enc = id3v2_version == 3 ? ID3v2_ENCODING_UTF16BOM :
- ID3v2_ENCODING_UTF8;
-
-
- avio_wb32(s->pb, MKBETAG(magic[0], magic[1], magic[2], id3v2_version));
- avio_w8(s->pb, 0);
- avio_w8(s->pb, 0); /* flags */
+ avio_wb32(pb, MKBETAG(magic[0], magic[1], magic[2], id3v2_version));
+ avio_w8(pb, 0);
+ avio_w8(pb, 0); /* flags */
/* reserve space for size */
- size_pos = avio_tell(s->pb);
- avio_wb32(s->pb, 0);
+ id3->size_pos = avio_tell(pb);
+ avio_wb32(pb, 0);
+}
+
+int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3)
+{
+ AVDictionaryEntry *t = NULL;
+ int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
+ ID3v2_ENCODING_UTF8;
ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL);
- if (id3v2_version == 3)
+ if (id3->version == 3)
id3v2_3_metadata_split_date(&s->metadata);
- else if (id3v2_version == 4)
+ else if (id3->version == 4)
ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL);
while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) {
int ret;
- if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_tags, enc)) > 0) {
- totlen += ret;
+ if ((ret = id3v2_check_write_tag(id3, s->pb, t, ff_id3v2_tags, enc)) > 0) {
+ id3->len += ret;
continue;
}
- if ((ret = id3v2_check_write_tag(s, t, id3v2_version == 3 ?
+ if ((ret = id3v2_check_write_tag(id3, s->pb, t, id3->version == 3 ?
ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
- totlen += ret;
+ id3->len += ret;
continue;
}
/* unknown tag, write as TXXX frame */
- if ((ret = id3v2_put_ttag(s, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
+ if ((ret = id3v2_put_ttag(id3, s->pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
return ret;
- totlen += ret;
+ id3->len += ret;
}
- cur_pos = avio_tell(s->pb);
- avio_seek(s->pb, size_pos, SEEK_SET);
- id3v2_put_size(s, totlen);
- avio_seek(s->pb, cur_pos, SEEK_SET);
+ return 0;
+}
+
+int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt)
+{
+ AVStream *st = s->streams[pkt->stream_index];
+ AVDictionaryEntry *e;
+
+ AVIOContext *dyn_buf;
+ uint8_t *buf;
+ const CodecMime *mime = ff_id3v2_mime_tags;
+ const char *mimetype = NULL, *desc = "";
+ int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM :
+ ID3v2_ENCODING_UTF8;
+ int i, len, type = 0;
+
+ /* get the mimetype*/
+ while (mime->id != CODEC_ID_NONE) {
+ if (mime->id == st->codec->codec_id) {
+ mimetype = mime->str;
+ break;
+ }
+ mime++;
+ }
+ if (!mimetype) {
+ av_log(s, AV_LOG_ERROR, "No mimetype is known for stream %d, cannot "
+ "write an attached picture.\n", st->index);
+ return AVERROR(EINVAL);
+ }
+
+ /* get the picture type */
+ e = av_dict_get(st->metadata, "comment", NULL, 0);
+ for (i = 0; e && i < FF_ARRAY_ELEMS(ff_id3v2_picture_types); i++) {
+ if (strstr(ff_id3v2_picture_types[i], e->value) == ff_id3v2_picture_types[i]) {
+ type = i;
+ break;
+ }
+ }
+
+ /* get the description */
+ if ((e = av_dict_get(st->metadata, "title", NULL, 0)))
+ desc = e->value;
+
+ /* start writing */
+ if (avio_open_dyn_buf(&dyn_buf) < 0)
+ return AVERROR(ENOMEM);
+
+ avio_w8(dyn_buf, enc);
+ avio_put_str(dyn_buf, mimetype);
+ avio_w8(dyn_buf, type);
+ id3v2_encode_string(dyn_buf, desc, enc);
+ avio_write(dyn_buf, pkt->data, pkt->size);
+ len = avio_close_dyn_buf(dyn_buf, &buf);
+
+ avio_wb32(s->pb, MKBETAG('A', 'P', 'I', 'C'));
+ if (id3->version == 3)
+ avio_wb32(s->pb, len);
+ else
+ id3v2_put_size(s->pb, len);
+ avio_wb16(s->pb, 0);
+ avio_write(s->pb, buf, len);
+ av_freep(&buf);
+
+ id3->len += len + ID3v2_HEADER_SIZE;
+
+ return 0;
+}
+
+void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb)
+{
+ int64_t cur_pos = avio_tell(pb);
+ avio_seek(pb, id3->size_pos, SEEK_SET);
+ id3v2_put_size(pb, id3->len);
+ avio_seek(pb, cur_pos, SEEK_SET);
+}
+
+int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version,
+ const char *magic)
+{
+ ID3v2EncContext id3 = { 0 };
+ int ret;
+
+ ff_id3v2_start(&id3, s->pb, id3v2_version, magic);
+ if ((ret = ff_id3v2_write_metadata(s, &id3)) < 0)
+ return ret;
+ ff_id3v2_finish(&id3, s->pb);
+
return 0;
}
diff --git a/libavformat/internal.h b/libavformat/internal.h
index f2b89a3384..8bc34bdb9a 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -37,6 +37,11 @@ typedef struct AVCodecTag {
unsigned int tag;
} AVCodecTag;
+typedef struct CodecMime{
+ char str[32];
+ enum CodecID id;
+} CodecMime;
+
#ifdef __GNUC__
#define dynarray_add(tab, nb_ptr, elem)\
do {\
diff --git a/libavformat/matroska.h b/libavformat/matroska.h
index ab7e3269fa..6f6ab1e929 100644
--- a/libavformat/matroska.h
+++ b/libavformat/matroska.h
@@ -24,6 +24,7 @@
#include "libavcodec/avcodec.h"
#include "metadata.h"
+#include "internal.h"
/* EBML version supported */
#define EBML_VERSION 1
@@ -250,11 +251,6 @@ typedef struct CodecTags{
enum CodecID id;
}CodecTags;
-typedef struct CodecMime{
- char str[32];
- enum CodecID id;
-}CodecMime;
-
/* max. depth in the EBML tree structure */
#define EBML_MAX_DEPTH 16
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 15df2bf198..4ad2051efc 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1223,6 +1223,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
if (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
unsigned int color_depth, len;
int color_greyscale;
+ int color_table_id;
st->codec->codec_id = id;
avio_rb16(pb); /* version */
@@ -1250,9 +1251,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
st->codec->codec_tag=MKTAG('I', '4', '2', '0');
st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */
- st->codec->color_table_id = avio_rb16(pb); /* colortable id */
+ color_table_id = avio_rb16(pb); /* colortable id */
av_dlog(c->fc, "depth %d, ctab id %d\n",
- st->codec->bits_per_coded_sample, st->codec->color_table_id);
+ st->codec->bits_per_coded_sample, color_table_id);
/* figure out the palette situation */
color_depth = st->codec->bits_per_coded_sample & 0x1F;
color_greyscale = st->codec->bits_per_coded_sample & 0x20;
@@ -1282,7 +1283,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries)
if (color_index < 0)
color_index = 0;
}
- } else if (st->codec->color_table_id) {
+ } else if (color_table_id) {
const uint8_t *color_table;
/* if flag bit 3 is set, use the default palette */
color_count = 1 << color_depth;
diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c
index 3bbc3e84f9..b2c1b4211e 100644
--- a/libavformat/mp3enc.c
+++ b/libavformat/mp3enc.c
@@ -84,6 +84,7 @@ static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf)
typedef struct MP3Context {
const AVClass *class;
+ ID3v2EncContext id3;
int id3v2_version;
int write_id3v1;
int64_t frames_offset;
@@ -93,60 +94,15 @@ typedef struct MP3Context {
uint32_t seen;
uint32_t pos;
uint64_t bag[VBR_NUM_BAGS];
-} MP3Context;
-
-static int mp2_write_trailer(struct AVFormatContext *s)
-{
- uint8_t buf[ID3v1_TAG_SIZE];
- MP3Context *mp3 = s->priv_data;
-
- /* write the id3v1 tag */
- if (mp3 && mp3->write_id3v1 && id3v1_create_tag(s, buf) > 0) {
- avio_write(s->pb, buf, ID3v1_TAG_SIZE);
- }
- /* write number of frames */
- if (mp3 && mp3->frames_offset) {
- avio_seek(s->pb, mp3->frames_offset, SEEK_SET);
- avio_wb32(s->pb, s->streams[0]->nb_frames);
- avio_seek(s->pb, 0, SEEK_END);
- }
-
- avio_flush(s->pb);
-
- return 0;
-}
-
-#if CONFIG_MP2_MUXER
-AVOutputFormat ff_mp2_muxer = {
- .name = "mp2",
- .long_name = NULL_IF_CONFIG_SMALL("MPEG audio layer 2"),
- .mime_type = "audio/x-mpeg",
- .extensions = "mp2,m2a",
- .audio_codec = CODEC_ID_MP2,
- .video_codec = CODEC_ID_NONE,
- .write_packet = ff_raw_write_packet,
- .write_trailer = mp2_write_trailer,
- .flags = AVFMT_NOTIMESTAMPS,
-};
-#endif
-
-#if CONFIG_MP3_MUXER
-
-static const AVOption options[] = {
- { "id3v2_version", "Select ID3v2 version to write. Currently 3 and 4 are supported.",
- offsetof(MP3Context, id3v2_version), AV_OPT_TYPE_INT, {.dbl = 4}, 3, 4, AV_OPT_FLAG_ENCODING_PARAM},
- { "write_id3v1", "Enable ID3v1 writing. ID3v1 tags are written in UTF-8 which may not be supported by most software.",
- offsetof(MP3Context, write_id3v1), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
- { NULL },
-};
+ /* index of the audio stream */
+ int audio_stream_idx;
+ /* number of attached pictures we still need to write */
+ int pics_to_write;
-static const AVClass mp3_muxer_class = {
- .class_name = "MP3 muxer",
- .item_name = av_default_item_name,
- .option = options,
- .version = LIBAVUTIL_VERSION_INT,
-};
+ /* audio packets are queued here until we get all the attached pictures */
+ AVPacketList *queue, *queue_end;
+} MP3Context;
static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
@@ -155,8 +111,8 @@ static const int64_t xing_offtbl[2][2] = {{32, 17}, {17,9}};
*/
static int mp3_write_xing(AVFormatContext *s)
{
- AVCodecContext *codec = s->streams[0]->codec;
MP3Context *mp3 = s->priv_data;
+ AVCodecContext *codec = s->streams[mp3->audio_stream_idx]->codec;
int bitrate_idx;
int best_bitrate_idx = -1;
int best_bitrate_error= INT_MAX;
@@ -166,6 +122,9 @@ static int mp3_write_xing(AVFormatContext *s)
int srate_idx, i, channels;
int needed;
+ if (!s->pb->seekable)
+ return 0;
+
for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++)
if (avpriv_mpa_freq_tab[i] == codec->sample_rate) {
srate_idx = i;
@@ -295,26 +254,7 @@ static void mp3_fix_xing(AVFormatContext *s)
avio_seek(s->pb, 0, SEEK_END);
}
-/**
- * Write an ID3v2 header at beginning of stream
- */
-
-static int mp3_write_header(struct AVFormatContext *s)
-{
- MP3Context *mp3 = s->priv_data;
- int ret;
-
- ret = ff_id3v2_write(s, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC);
- if (ret < 0)
- return ret;
-
- if (s->pb->seekable)
- mp3_write_xing(s);
-
- return 0;
-}
-
-static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt)
+static int mp3_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
{
if (! pkt || ! pkt->data || pkt->size < 4)
return ff_raw_write_packet(s, pkt);
@@ -350,6 +290,175 @@ static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt)
}
}
+static int mp3_queue_flush(AVFormatContext *s)
+{
+ MP3Context *mp3 = s->priv_data;
+ AVPacketList *pktl;
+ int ret = 0, write = 1;
+
+ ff_id3v2_finish(&mp3->id3, s->pb);
+ mp3_write_xing(s);
+
+ while ((pktl = mp3->queue)) {
+ if (write && (ret = mp3_write_packet_internal(s, &pktl->pkt)) < 0)
+ write = 0;
+ av_free_packet(&pktl->pkt);
+ mp3->queue = pktl->next;
+ av_freep(&pktl);
+ }
+ mp3->queue_end = NULL;
+ return ret;
+}
+
+static int mp2_write_trailer(struct AVFormatContext *s)
+{
+ uint8_t buf[ID3v1_TAG_SIZE];
+ MP3Context *mp3 = s->priv_data;
+
+ if (mp3 && mp3->pics_to_write) {
+ av_log(s, AV_LOG_WARNING, "No packets were sent for some of the "
+ "attached pictures.\n");
+ mp3_queue_flush(s);
+ }
+
+ /* write the id3v1 tag */
+ if (mp3 && mp3->write_id3v1 && id3v1_create_tag(s, buf) > 0) {
+ avio_write(s->pb, buf, ID3v1_TAG_SIZE);
+ }
+
+ /* write number of frames */
+ if (mp3 && mp3->frames_offset) {
+ avio_seek(s->pb, mp3->frames_offset, SEEK_SET);
+ avio_wb32(s->pb, s->streams[mp3->audio_stream_idx]->nb_frames);
+ avio_seek(s->pb, 0, SEEK_END);
+ }
+
+ avio_flush(s->pb);
+
+ return 0;
+}
+
+#if CONFIG_MP2_MUXER
+AVOutputFormat ff_mp2_muxer = {
+ .name = "mp2",
+ .long_name = NULL_IF_CONFIG_SMALL("MPEG audio layer 2"),
+ .mime_type = "audio/x-mpeg",
+ .extensions = "mp2,m2a",
+ .audio_codec = CODEC_ID_MP2,
+ .video_codec = CODEC_ID_NONE,
+ .write_packet = ff_raw_write_packet,
+ .write_trailer = mp2_write_trailer,
+ .flags = AVFMT_NOTIMESTAMPS,
+};
+#endif
+
+#if CONFIG_MP3_MUXER
+
+static const AVOption options[] = {
+ { "id3v2_version", "Select ID3v2 version to write. Currently 3 and 4 are supported.",
+ offsetof(MP3Context, id3v2_version), AV_OPT_TYPE_INT, {.dbl = 4}, 3, 4, AV_OPT_FLAG_ENCODING_PARAM},
+ { "write_id3v1", "Enable ID3v1 writing. ID3v1 tags are written in UTF-8 which may not be supported by most software.",
+ offsetof(MP3Context, write_id3v1), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
+ { NULL },
+};
+
+static const AVClass mp3_muxer_class = {
+ .class_name = "MP3 muxer",
+ .item_name = av_default_item_name,
+ .option = options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MP3Context *mp3 = s->priv_data;
+
+ if (pkt->stream_index == mp3->audio_stream_idx) {
+ if (mp3->pics_to_write) {
+ /* buffer audio packets until we get all the pictures */
+ AVPacketList *pktl = av_mallocz(sizeof(*pktl));
+ if (!pktl)
+ return AVERROR(ENOMEM);
+
+ pktl->pkt = *pkt;
+ pkt->destruct = NULL;
+
+ if (mp3->queue_end)
+ mp3->queue_end->next = pktl;
+ else
+ mp3->queue = pktl;
+ mp3->queue_end = pktl;
+ } else
+ return mp3_write_packet_internal(s, pkt);
+ } else {
+ int ret;
+
+ /* warn only once for each stream */
+ if (s->streams[pkt->stream_index]->nb_frames == 1) {
+ av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
+ " ignoring.\n", pkt->stream_index);
+ }
+ if (!mp3->pics_to_write || s->streams[pkt->stream_index]->nb_frames >= 1)
+ return 0;
+
+ if ((ret = ff_id3v2_write_apic(s, &mp3->id3, pkt)) < 0)
+ return ret;
+ mp3->pics_to_write--;
+
+ /* flush the buffered audio packets */
+ if (!mp3->pics_to_write &&
+ (ret = mp3_queue_flush(s)) < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * Write an ID3v2 header at beginning of stream
+ */
+
+static int mp3_write_header(struct AVFormatContext *s)
+{
+ MP3Context *mp3 = s->priv_data;
+ int ret, i;
+
+ /* check the streams -- we want exactly one audio and arbitrary number of
+ * video (attached pictures) */
+ mp3->audio_stream_idx = -1;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (mp3->audio_stream_idx >= 0 || st->codec->codec_id != CODEC_ID_MP3) {
+ av_log(s, AV_LOG_ERROR, "Invalid audio stream. Exactly one MP3 "
+ "audio stream is required.\n");
+ return AVERROR(EINVAL);
+ }
+ mp3->audio_stream_idx = i;
+ } else if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) {
+ av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in MP3.\n");
+ return AVERROR(EINVAL);
+ }
+ }
+ if (mp3->audio_stream_idx < 0) {
+ av_log(s, AV_LOG_ERROR, "No audio stream present.\n");
+ return AVERROR(EINVAL);
+ }
+ mp3->pics_to_write = s->nb_streams - 1;
+
+ ff_id3v2_start(&mp3->id3, s->pb, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC);
+ ret = ff_id3v2_write_metadata(s, &mp3->id3);
+ if (ret < 0)
+ return ret;
+
+ if (!mp3->pics_to_write) {
+ ff_id3v2_finish(&mp3->id3, s->pb);
+ mp3_write_xing(s);
+ }
+
+ return 0;
+}
+
static int mp3_write_trailer(AVFormatContext *s)
{
MP3Context *mp3 = s->priv_data;
@@ -371,7 +480,7 @@ AVOutputFormat ff_mp3_muxer = {
.extensions = "mp3",
.priv_data_size = sizeof(MP3Context),
.audio_codec = CODEC_ID_MP3,
- .video_codec = CODEC_ID_NONE,
+ .video_codec = CODEC_ID_PNG,
.write_header = mp3_write_header,
.write_packet = mp3_write_packet,
.write_trailer = mp3_write_trailer,
diff --git a/libavformat/omadec.c b/libavformat/omadec.c
index 97aaf175ab..a62b560504 100644
--- a/libavformat/omadec.c
+++ b/libavformat/omadec.c
@@ -270,7 +270,7 @@ static int oma_read_header(AVFormatContext *s)
ID3v2ExtraMeta *extra_meta = NULL;
OMAContext *oc = s->priv_data;
- ff_id3v2_read_all(s, ID3v2_EA3_MAGIC, &extra_meta);
+ ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta);
ret = avio_read(s->pb, buf, EA3_HEADER_SIZE);
if (ret < EA3_HEADER_SIZE)
return -1;
diff --git a/libavformat/omaenc.c b/libavformat/omaenc.c
index e932b4bbc1..c3ee0e8de1 100644
--- a/libavformat/omaenc.c
+++ b/libavformat/omaenc.c
@@ -49,7 +49,7 @@ static av_cold int oma_write_header(AVFormatContext *s)
}
/* Metadata; OpenMG does not support ID3v2.4 */
- ff_id3v2_write(s, 3, ID3v2_EA3_MAGIC);
+ ff_id3v2_write_simple(s, 3, ID3v2_EA3_MAGIC);
ffio_wfourcc(s->pb, "EA3\0");
avio_w8(s->pb, EA3_HEADER_SIZE >> 7);
diff --git a/libavformat/psxstr.c b/libavformat/psxstr.c
index d657197d6f..24f1c08617 100644
--- a/libavformat/psxstr.c
+++ b/libavformat/psxstr.c
@@ -299,4 +299,5 @@ AVInputFormat ff_str_demuxer = {
.read_header = str_read_header,
.read_packet = str_read_packet,
.read_close = str_read_close,
+ .flags = AVFMT_NO_BYTE_SEEK,
};
diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c
index 32288684eb..88a0527566 100644
--- a/libavformat/rtpenc.c
+++ b/libavformat/rtpenc.c
@@ -112,7 +112,7 @@ static int rtp_write_header(AVFormatContext *s1)
if (s->max_packet_size) {
if (s1->pb->max_packet_size)
- s->max_packet_size = FFMIN(s->max_payload_size,
+ s->max_packet_size = FFMIN(s->max_packet_size,
s1->pb->max_packet_size);
} else
s->max_packet_size = s1->pb->max_packet_size;
diff --git a/libavformat/swfdec.c b/libavformat/swfdec.c
index a84d3808bf..4a2c3d5403 100644
--- a/libavformat/swfdec.c
+++ b/libavformat/swfdec.c
@@ -113,7 +113,6 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->codec_id = ff_codec_get_id(swf_codec_tags, avio_r8(pb));
avpriv_set_pts_info(vst, 16, 256, swf->frame_rate);
- vst->codec->time_base = (AVRational){ 256, swf->frame_rate };
len -= 8;
} else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) {
/* streaming found */
@@ -186,7 +185,6 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt)
vst->codec->codec_type = AVMEDIA_TYPE_VIDEO;
vst->codec->codec_id = CODEC_ID_MJPEG;
avpriv_set_pts_info(vst, 64, 256, swf->frame_rate);
- vst->codec->time_base = (AVRational){ 256, swf->frame_rate };
st = vst;
}
avio_rl16(pb); /* BITMAP_ID */
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 44cef9e8ab..e84cd7657a 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -545,11 +545,29 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o
return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0);
}
+static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
+ AVPacketList **plast_pktl){
+ AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
+ if (!pktl)
+ return NULL;
+
+ if (*packet_buffer)
+ (*plast_pktl)->next = pktl;
+ else
+ *packet_buffer = pktl;
+
+ /* add the packet in the buffered packet list */
+ *plast_pktl = pktl;
+ pktl->pkt= *pkt;
+ return &pktl->pkt;
+}
+
int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options)
{
AVFormatContext *s = *ps;
- int ret = 0;
+ int i, ret = 0;
AVDictionary *tmp = NULL;
+ ID3v2ExtraMeta *id3v2_extra_meta = NULL;
if (!s && !(s = avformat_alloc_context()))
return AVERROR(ENOMEM);
@@ -592,12 +610,25 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */
if (s->pb)
- ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC);
+ ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)
if ((ret = s->iformat->read_header(s)) < 0)
goto fail;
+ if (id3v2_extra_meta &&
+ (ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)
+ goto fail;
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
+
+ /* queue attached pictures */
+ for (i = 0; i < s->nb_streams; i++)
+ if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC) {
+ AVPacket copy = s->streams[i]->attached_pic;
+ copy.destruct = NULL;
+ add_to_pktbuf(&s->raw_packet_buffer, &copy, &s->raw_packet_buffer_end);
+ }
+
if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)
s->data_offset = avio_tell(s->pb);
@@ -611,6 +642,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma
return 0;
fail:
+ ff_id3v2_free_extra_meta(&id3v2_extra_meta);
av_dict_free(&tmp);
if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))
avio_close(s->pb);
@@ -621,23 +653,6 @@ fail:
/*******************************************************/
-static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
- AVPacketList **plast_pktl){
- AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
- if (!pktl)
- return NULL;
-
- if (*packet_buffer)
- (*plast_pktl)->next = pktl;
- else
- *packet_buffer = pktl;
-
- /* add the packet in the buffered packet list */
- *plast_pktl = pktl;
- pktl->pkt= *pkt;
- return &pktl->pkt;
-}
-
int av_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, i;
@@ -2722,6 +2737,8 @@ void avformat_free_context(AVFormatContext *s)
av_parser_close(st->parser);
av_free_packet(&st->cur_pkt);
}
+ if (st->attached_pic.data)
+ av_free_packet(&st->attached_pic);
av_dict_free(&st->metadata);
av_freep(&st->index_entries);
av_freep(&st->codec->extradata);
diff --git a/libavformat/version.h b/libavformat/version.h
index 1fafa17dfc..0dc68152c3 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -30,7 +30,7 @@
#include "libavutil/avutil.h"
#define LIBAVFORMAT_VERSION_MAJOR 54
-#define LIBAVFORMAT_VERSION_MINOR 1
+#define LIBAVFORMAT_VERSION_MINOR 2
#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
diff --git a/libavformat/vqf.c b/libavformat/vqf.c
index 8cd69232ce..4664c0068f 100644
--- a/libavformat/vqf.c
+++ b/libavformat/vqf.c
@@ -220,12 +220,12 @@ static int vqf_read_packet(AVFormatContext *s, AVPacket *pkt)
int ret;
int size = (c->frame_bit_len - c->remaining_bits + 7)>>3;
- pkt->pos = avio_tell(s->pb);
- pkt->stream_index = 0;
-
if (av_new_packet(pkt, size+2) < 0)
return AVERROR(EIO);
+ pkt->pos = avio_tell(s->pb);
+ pkt->stream_index = 0;
+
pkt->data[0] = 8 - c->remaining_bits; // Number of bits to skip
pkt->data[1] = c->last_frame_bits;
ret = avio_read(s->pb, pkt->data+2, size);