]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/apetag.c
mpegts: use avcodec_get_type() to set codec_type
[ffmpeg] / libavformat / apetag.c
index dd746313b5640355a6f701f0ce0687e741a56495..5591555377e2b11a4e94b54733bb443cfb4dac68 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <inttypes.h>
+
 #include "libavutil/intreadwrite.h"
 #include "libavutil/dict.h"
 #include "avformat.h"
+#include "avio_internal.h"
 #include "apetag.h"
 #include "internal.h"
 
 #define APE_TAG_VERSION               2000
 #define APE_TAG_FOOTER_BYTES          32
 #define APE_TAG_FLAG_CONTAINS_HEADER  (1 << 31)
+#define APE_TAG_FLAG_CONTAINS_FOOTER  (1 << 30)
 #define APE_TAG_FLAG_IS_HEADER        (1 << 29)
 #define APE_TAG_FLAG_IS_BINARY        (1 << 1)
 
@@ -36,7 +40,7 @@ static int ape_tag_read_field(AVFormatContext *s)
 {
     AVIOContext *pb = s->pb;
     uint8_t key[1024], *value;
-    uint32_t size, flags;
+    int64_t size, flags;
     int i, c;
 
     size = avio_rl32(pb);  /* field size */
@@ -53,11 +57,13 @@ static int ape_tag_read_field(AVFormatContext *s)
         av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key);
         return -1;
     }
-    if (size >= UINT_MAX)
-        return -1;
+    if (size > INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE) {
+        av_log(s, AV_LOG_ERROR, "APE tag size too large.\n");
+        return AVERROR_INVALIDDATA;
+    }
     if (flags & APE_TAG_FLAG_IS_BINARY) {
         uint8_t filename[1024];
-        enum CodecID id;
+        enum AVCodecID id;
         AVStream *st = avformat_new_stream(s, NULL);
         if (!st)
             return AVERROR(ENOMEM);
@@ -70,7 +76,7 @@ static int ape_tag_read_field(AVFormatContext *s)
 
         av_dict_set(&st->metadata, key, filename, 0);
 
-        if ((id = ff_guess_image2_codec(filename)) != CODEC_ID_NONE) {
+        if ((id = ff_guess_image2_codec(filename)) != AV_CODEC_ID_NONE) {
             AVPacket pkt;
             int ret;
 
@@ -88,7 +94,7 @@ static int ape_tag_read_field(AVFormatContext *s)
             st->attached_pic.stream_index = st->index;
             st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
         } else {
-            st->codec->extradata = av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);
+            st->codec->extradata = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
             if (!st->codec->extradata)
                 return AVERROR(ENOMEM);
             if (avio_read(pb, st->codec->extradata, size) != size) {
@@ -116,7 +122,7 @@ static int ape_tag_read_field(AVFormatContext *s)
 int64_t ff_ape_parse_tag(AVFormatContext *s)
 {
     AVIOContext *pb = s->pb;
-    int file_size = avio_size(pb);
+    int64_t file_size = avio_size(pb);
     uint32_t val, fields, tag_bytes;
     uint8_t buf[8];
     int64_t tag_start;
@@ -144,22 +150,22 @@ int64_t ff_ape_parse_tag(AVFormatContext *s)
         return 0;
     }
 
-    tag_start = file_size - tag_bytes - APE_TAG_FOOTER_BYTES;
-    if (tag_start < 0) {
-        av_log(s, AV_LOG_ERROR, "Invalid tag size %u.\n", tag_bytes);
+    if (tag_bytes > file_size - APE_TAG_FOOTER_BYTES) {
+        av_log(s, AV_LOG_ERROR, "Invalid tag size %"PRIu32".\n", tag_bytes);
         return 0;
     }
+    tag_start = file_size - tag_bytes - APE_TAG_FOOTER_BYTES;
 
     fields = avio_rl32(pb);    /* number of fields */
     if (fields > 65536) {
-        av_log(s, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields);
+        av_log(s, AV_LOG_ERROR, "Too many tag fields (%"PRIu32")\n", fields);
         return 0;
     }
 
     val = avio_rl32(pb);       /* flags */
     if (val & APE_TAG_FLAG_IS_HEADER) {
         av_log(s, AV_LOG_ERROR, "APE Tag is a header\n");
-        return;
+        return 0;
     }
 
     avio_seek(pb, file_size - tag_bytes, SEEK_SET);
@@ -169,3 +175,57 @@ int64_t ff_ape_parse_tag(AVFormatContext *s)
 
     return tag_start;
 }
+
+int ff_ape_write_tag(AVFormatContext *s)
+{
+    AVDictionaryEntry *e = NULL;
+    int64_t start, end;
+    int size, count = 0;
+
+    if (!s->pb->seekable)
+        return 0;
+
+    start = avio_tell(s->pb);
+
+    // header
+    avio_write(s->pb, "APETAGEX", 8);   // id
+    avio_wl32 (s->pb, APE_TAG_VERSION); // version
+    avio_wl32(s->pb, 0);                // reserve space for size
+    avio_wl32(s->pb, 0);                // reserve space for tag count
+
+    // flags
+    avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER |
+                     APE_TAG_FLAG_IS_HEADER);
+    ffio_fill(s->pb, 0, 8);             // reserved
+
+    while ((e = av_dict_get(s->metadata, "", e, AV_DICT_IGNORE_SUFFIX))) {
+        int val_len = strlen(e->value);
+
+        avio_wl32(s->pb, val_len);            // value length
+        avio_wl32(s->pb, 0);                  // item flags
+        avio_put_str(s->pb, e->key);          // key
+        avio_write(s->pb, e->value, val_len); // value
+        count++;
+    }
+
+    size = avio_tell(s->pb) - start;
+
+    // footer
+    avio_write(s->pb, "APETAGEX", 8);   // id
+    avio_wl32 (s->pb, APE_TAG_VERSION); // version
+    avio_wl32(s->pb, size);             // size
+    avio_wl32(s->pb, count);            // tag count
+
+    // flags
+    avio_wl32(s->pb, APE_TAG_FLAG_CONTAINS_HEADER | APE_TAG_FLAG_CONTAINS_FOOTER);
+    ffio_fill(s->pb, 0, 8);             // reserved
+
+    // update values in the header
+    end = avio_tell(s->pb);
+    avio_seek(s->pb, start + 12, SEEK_SET);
+    avio_wl32(s->pb, size);
+    avio_wl32(s->pb, count);
+    avio_seek(s->pb, end, SEEK_SET);
+
+    return 0;
+}