00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <strings.h>
00023 #include "avformat.h"
00024 #include "id3v1.h"
00025 #include "id3v2.h"
00026 #include "libavutil/intreadwrite.h"
00027 #include "libavutil/opt.h"
00028
00029 static int id3v1_set_string(AVFormatContext *s, const char *key,
00030 uint8_t *buf, int buf_size)
00031 {
00032 AVMetadataTag *tag;
00033 if ((tag = av_metadata_get(s->metadata, key, NULL, 0)))
00034 strncpy(buf, tag->value, buf_size);
00035 return !!tag;
00036 }
00037
00038 static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf)
00039 {
00040 AVMetadataTag *tag;
00041 int i, count = 0;
00042
00043 memset(buf, 0, ID3v1_TAG_SIZE);
00044 buf[0] = 'T';
00045 buf[1] = 'A';
00046 buf[2] = 'G';
00047 count += id3v1_set_string(s, "TIT2", buf + 3, 30);
00048 count += id3v1_set_string(s, "TPE1", buf + 33, 30);
00049 count += id3v1_set_string(s, "TALB", buf + 63, 30);
00050 count += id3v1_set_string(s, "TDRL", buf + 93, 4);
00051 count += id3v1_set_string(s, "comment", buf + 97, 30);
00052 if ((tag = av_metadata_get(s->metadata, "TRCK", NULL, 0))) {
00053 buf[125] = 0;
00054 buf[126] = atoi(tag->value);
00055 count++;
00056 }
00057 buf[127] = 0xFF;
00058 if ((tag = av_metadata_get(s->metadata, "TCON", NULL, 0))) {
00059 for(i = 0; i <= ID3v1_GENRE_MAX; i++) {
00060 if (!strcasecmp(tag->value, ff_id3v1_genre_str[i])) {
00061 buf[127] = i;
00062 count++;
00063 break;
00064 }
00065 }
00066 }
00067 return count;
00068 }
00069
00070
00071
00072 static void id3v2_put_size(AVFormatContext *s, int size)
00073 {
00074 avio_w8(s->pb, size >> 21 & 0x7f);
00075 avio_w8(s->pb, size >> 14 & 0x7f);
00076 avio_w8(s->pb, size >> 7 & 0x7f);
00077 avio_w8(s->pb, size & 0x7f);
00078 }
00079
00080 static int string_is_ascii(const uint8_t *str)
00081 {
00082 while (*str && *str < 128) str++;
00083 return !*str;
00084 }
00085
00091 static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2,
00092 uint32_t tag, enum ID3v2Encoding enc)
00093 {
00094 int len;
00095 uint8_t *pb;
00096 int (*put)(AVIOContext*, const char*);
00097 AVIOContext *dyn_buf;
00098 if (url_open_dyn_buf(&dyn_buf) < 0)
00099 return AVERROR(ENOMEM);
00100
00101
00102
00103 if (enc == ID3v2_ENCODING_UTF16BOM && string_is_ascii(str1) &&
00104 (!str2 || string_is_ascii(str2)))
00105 enc = ID3v2_ENCODING_ISO8859;
00106
00107 avio_w8(dyn_buf, enc);
00108 if (enc == ID3v2_ENCODING_UTF16BOM) {
00109 avio_wl16(dyn_buf, 0xFEFF);
00110 put = avio_put_str16le;
00111 } else
00112 put = avio_put_str;
00113
00114 put(dyn_buf, str1);
00115 if (str2)
00116 put(dyn_buf, str2);
00117 len = url_close_dyn_buf(dyn_buf, &pb);
00118
00119 avio_wb32(s->pb, tag);
00120 id3v2_put_size(s, len);
00121 avio_wb16(s->pb, 0);
00122 avio_write(s->pb, pb, len);
00123
00124 av_freep(&pb);
00125 return len + ID3v2_HEADER_SIZE;
00126 }
00127
00128
00129 static int mp3_write_packet(struct AVFormatContext *s, AVPacket *pkt)
00130 {
00131 avio_write(s->pb, pkt->data, pkt->size);
00132 put_flush_packet(s->pb);
00133 return 0;
00134 }
00135
00136 static int mp3_write_trailer(struct AVFormatContext *s)
00137 {
00138 uint8_t buf[ID3v1_TAG_SIZE];
00139
00140
00141 if (id3v1_create_tag(s, buf) > 0) {
00142 avio_write(s->pb, buf, ID3v1_TAG_SIZE);
00143 put_flush_packet(s->pb);
00144 }
00145 return 0;
00146 }
00147
00148 #if CONFIG_MP2_MUXER
00149 AVOutputFormat ff_mp2_muxer = {
00150 "mp2",
00151 NULL_IF_CONFIG_SMALL("MPEG audio layer 2"),
00152 "audio/x-mpeg",
00153 "mp2,m2a",
00154 0,
00155 CODEC_ID_MP2,
00156 CODEC_ID_NONE,
00157 NULL,
00158 mp3_write_packet,
00159 mp3_write_trailer,
00160 };
00161 #endif
00162
00163 #if CONFIG_MP3_MUXER
00164 typedef struct MP3Context {
00165 const AVClass *class;
00166 int id3v2_version;
00167 } MP3Context;
00168
00169 static const AVOption options[] = {
00170 { "id3v2_version", "Select ID3v2 version to write. Currently 3 and 4 are supported.",
00171 offsetof(MP3Context, id3v2_version), FF_OPT_TYPE_INT, 4, 3, 4, AV_OPT_FLAG_ENCODING_PARAM},
00172 { NULL },
00173 };
00174
00175 static const AVClass mp3_muxer_class = {
00176 "MP3 muxer",
00177 av_default_item_name,
00178 options,
00179 LIBAVUTIL_VERSION_INT,
00180 };
00181
00182 static int id3v2_check_write_tag(AVFormatContext *s, AVMetadataTag *t, const char table[][4],
00183 enum ID3v2Encoding enc)
00184 {
00185 uint32_t tag;
00186 int i;
00187
00188 if (t->key[0] != 'T' || strlen(t->key) != 4)
00189 return -1;
00190 tag = AV_RB32(t->key);
00191 for (i = 0; *table[i]; i++)
00192 if (tag == AV_RB32(table[i]))
00193 return id3v2_put_ttag(s, t->value, NULL, tag, enc);
00194 return -1;
00195 }
00196
00201 static int mp3_write_header(struct AVFormatContext *s)
00202 {
00203 MP3Context *mp3 = s->priv_data;
00204 AVMetadataTag *t = NULL;
00205 int totlen = 0, enc = mp3->id3v2_version == 3 ? ID3v2_ENCODING_UTF16BOM :
00206 ID3v2_ENCODING_UTF8;
00207 int64_t size_pos, cur_pos;
00208
00209 avio_wb32(s->pb, MKBETAG('I', 'D', '3', mp3->id3v2_version));
00210 avio_w8(s->pb, 0);
00211 avio_w8(s->pb, 0);
00212
00213
00214 size_pos = avio_tell(s->pb);
00215 avio_wb32(s->pb, 0);
00216
00217 ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL);
00218 if (mp3->id3v2_version == 4)
00219 ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL);
00220
00221 while ((t = av_metadata_get(s->metadata, "", t, AV_METADATA_IGNORE_SUFFIX))) {
00222 int ret;
00223
00224 if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_tags, enc)) > 0) {
00225 totlen += ret;
00226 continue;
00227 }
00228 if ((ret = id3v2_check_write_tag(s, t, mp3->id3v2_version == 3 ?
00229 ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) {
00230 totlen += ret;
00231 continue;
00232 }
00233
00234
00235 if ((ret = id3v2_put_ttag(s, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0)
00236 return ret;
00237 totlen += ret;
00238 }
00239
00240 cur_pos = avio_tell(s->pb);
00241 avio_seek(s->pb, size_pos, SEEK_SET);
00242 id3v2_put_size(s, totlen);
00243 avio_seek(s->pb, cur_pos, SEEK_SET);
00244
00245 return 0;
00246 }
00247
00248 AVOutputFormat ff_mp3_muxer = {
00249 "mp3",
00250 NULL_IF_CONFIG_SMALL("MPEG audio layer 3"),
00251 "audio/x-mpeg",
00252 "mp3",
00253 sizeof(MP3Context),
00254 CODEC_ID_MP3,
00255 CODEC_ID_NONE,
00256 mp3_write_header,
00257 mp3_write_packet,
00258 mp3_write_trailer,
00259 AVFMT_NOTIMESTAMPS,
00260 .priv_class = &mp3_muxer_class,
00261 };
00262 #endif