Merge remote-tracking branch 'qatar/master'

* qatar/master:
  swfdec: Add support for sample_rate_code 0 (5512 Hz)
  dct-test: factor out some common code and do whas was likely intended
  doc: library versions need to be bumped in version.h
  Revert "ffmpeg: get rid of useless AVInputStream.nb_streams."
  Remove some forgotten AVCodecContext.palctrl usage.
  lavc/utils: move avcodec_init() higher in the file.
  lavc: replace some deprecated FF_*_TYPE with AV_PICTURE_TYPE_*
  ac3dec: actually use drc_scale private option
  lavc: undeprecate AVPALETTE_SIZE and AVPALETTE_COUNT macros
  alsa: add missing header
  msmpeg4: remove leftover unused debug variable declaration
  Fix assert() calls that need updates after FF_COMMON_FRAME macro elimination.
  Fix av_dlog invocations with wrong or missing logging context.
  vf_yadif: add support to yuva420p
  vf_yadif: correct documentation on the parity parameter
  vf_yadif: copy buffer properties like aspect for second frame as well
  oma: support for encrypted files
  id3v2: add support for non-text and GEOB type tag frames
  des: add possibility to calculate DES-CBC-MAC with small buffer

Conflicts:
	ffmpeg.c
	libavcodec/dct-test.c
	libavformat/mpegts.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Michael Niedermayer
2011-09-21 21:25:43 +02:00
22 changed files with 644 additions and 173 deletions

View File

@ -66,63 +66,129 @@ static unsigned int get_size(AVIOContext *s, int len)
return v;
}
static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
/**
* Free GEOB type extra metadata.
*/
static void free_geobtag(ID3v2ExtraMetaGEOB *geob)
{
char *q, dst[512];
const char *val = NULL;
int len, dstlen = sizeof(dst) - 1;
unsigned genre;
av_free(geob->mime_type);
av_free(geob->file_name);
av_free(geob->description);
av_free(geob->data);
av_free(geob);
}
/**
* Decode characters to UTF-8 according to encoding type. The decoded buffer is
* always null terminated.
*
* @param dst Pointer where the address of the buffer with the decoded bytes is
* stored. Buffer must be freed by caller.
* @param dstlen Pointer to an int where the length of the decoded string
* is stored (in bytes, incl. null termination)
* @param maxread Pointer to maximum number of characters to read from the
* AVIOContext. After execution the value is decremented by the number of bytes
* actually read.
* @seeknull If true, decoding stops after the first U+0000 character found, if
* there is any before maxread is reached
* @returns 0 if no error occured, dst is uninitialized on error
*/
static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
uint8_t **dst, int *dstlen, int *maxread, const int seeknull)
{
int len, ret;
uint8_t tmp;
uint32_t ch = 1;
int left = *maxread;
unsigned int (*get)(AVIOContext*) = avio_rb16;
AVIOContext *dynbuf;
dst[0] = 0;
if (taglen < 1)
return;
if ((ret = avio_open_dyn_buf(&dynbuf)) < 0) {
av_log(s, AV_LOG_ERROR, "Error opening memory stream\n");
return ret;
}
taglen--; /* account for encoding type byte */
switch (avio_r8(pb)) { /* encoding type */
switch (encoding) {
case ID3v2_ENCODING_ISO8859:
q = dst;
while (taglen-- && q - dst < dstlen - 7) {
uint8_t tmp;
PUT_UTF8(avio_r8(pb), tmp, *q++ = tmp;)
while (left && (!seeknull || ch)) {
ch = avio_r8(pb);
PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
left--;
}
*q = 0;
break;
case ID3v2_ENCODING_UTF16BOM:
taglen -= 2;
if ((left -= 2) < 0) {
av_log(s, AV_LOG_ERROR, "Cannot read BOM value, input too short\n");
avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
av_freep(dst);
return AVERROR_INVALIDDATA;
}
switch (avio_rb16(pb)) {
case 0xfffe:
get = avio_rl16;
case 0xfeff:
break;
default:
av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
return;
av_log(s, AV_LOG_ERROR, "Incorrect BOM value\n");
avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
av_freep(dst);
*maxread = left;
return AVERROR_INVALIDDATA;
}
// fall-through
case ID3v2_ENCODING_UTF16BE:
q = dst;
while (taglen > 1 && q - dst < dstlen - 7) {
uint32_t ch;
uint8_t tmp;
GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(pb) : 0), break;)
PUT_UTF8(ch, tmp, *q++ = tmp;)
while ((left > 1) && (!seeknull || ch)) {
GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;)
PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
}
*q = 0;
if (left < 0)
left += 2; /* did not read last char from pb */
break;
case ID3v2_ENCODING_UTF8:
len = FFMIN(taglen, dstlen);
avio_read(pb, dst, len);
dst[len] = 0;
while (left && (!seeknull || ch)) {
ch = avio_r8(pb);
avio_w8(dynbuf, ch);
left--;
}
break;
default:
av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s.\n", key);
av_log(s, AV_LOG_WARNING, "Unknown encoding\n");
}
if (ch)
avio_w8(dynbuf, 0);
len = avio_close_dyn_buf(dynbuf, (uint8_t **)dst);
if (dstlen)
*dstlen = len;
*maxread = left;
return 0;
}
/**
* Parse a text tag.
*/
static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *key)
{
uint8_t *dst;
const char *val = NULL;
int len, dstlen;
unsigned genre;
if (taglen < 1)
return;
taglen--; /* account for encoding type byte */
if (decode_str(s, pb, avio_r8(pb), &dst, &dstlen, &taglen, 0) < 0) {
av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
return;
}
if (!(strcmp(key, "TCON") && strcmp(key, "TCO"))
@ -141,6 +207,82 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, const cha
if (val)
av_dict_set(&s->metadata, key, val, AV_DICT_DONT_OVERWRITE);
av_free(dst);
}
/**
* Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
*/
static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta)
{
ID3v2ExtraMetaGEOB *geob_data = NULL;
ID3v2ExtraMeta *new_extra = NULL;
char encoding;
unsigned int len;
if (taglen < 1)
return;
geob_data = av_mallocz(sizeof(ID3v2ExtraMetaGEOB));
if (!geob_data) {
av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMetaGEOB));
return;
}
new_extra = av_mallocz(sizeof(ID3v2ExtraMeta));
if (!new_extra) {
av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMeta));
goto fail;
}
/* read encoding type byte */
encoding = avio_r8(pb);
taglen--;
/* read MIME type (always ISO-8859) */
if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type, NULL, &taglen, 1) < 0
|| taglen <= 0)
goto fail;
/* read file name */
if (decode_str(s, pb, encoding, &geob_data->file_name, NULL, &taglen, 1) < 0
|| taglen <= 0)
goto fail;
/* read content description */
if (decode_str(s, pb, encoding, &geob_data->description, NULL, &taglen, 1) < 0
|| taglen < 0)
goto fail;
if (taglen) {
/* save encapsulated binary data */
geob_data->data = av_malloc(taglen);
if (!geob_data->data) {
av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", taglen);
goto fail;
}
if ((len = avio_read(pb, geob_data->data, taglen)) < taglen)
av_log(s, AV_LOG_WARNING, "Error reading GEOB frame, data truncated.\n");
geob_data->datasize = len;
} else {
geob_data->data = NULL;
geob_data->datasize = 0;
}
/* add data to the list */
new_extra->tag = "GEOB";
new_extra->data = geob_data;
new_extra->next = *extra_meta;
*extra_meta = new_extra;
return;
fail:
av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", tag);
free_geobtag(geob_data);
av_free(new_extra);
return;
}
static int is_number(const char *str)
@ -189,7 +331,27 @@ finish:
av_dict_set(m, "date", date, 0);
}
static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
/**
* Get the corresponding ID3v2EMFunc struct for a tag.
* @param isv34 Determines if v2.2 or v2.3/4 strings are used
* @return A pointer to the ID3v2EMFunc struct if found, NULL otherwise.
*/
static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
{
int i = 0;
while (ff_id3v2_extra_meta_funcs[i].tag3) {
if (!memcmp(tag,
(isv34 ?
ff_id3v2_extra_meta_funcs[i].tag4 :
ff_id3v2_extra_meta_funcs[i].tag3),
(isv34 ? 4 : 3)))
return &ff_id3v2_extra_meta_funcs[i];
i++;
}
return NULL;
}
static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta)
{
int isv34, unsync;
unsigned tlen;
@ -198,8 +360,10 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
int taghdrlen;
const char *reason = NULL;
AVIOContext pb;
AVIOContext *pbx;
unsigned char *buffer = NULL;
int buffer_size = 0;
void (*extra_func)(AVFormatContext*, AVIOContext*, int, char*, ID3v2ExtraMeta**) = NULL;
switch (version) {
case 2:
@ -264,7 +428,8 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
avio_skip(s->pb, tlen);
} else if (tag[0] == 'T') {
/* check for text tag or supported special meta tag */
} else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)->read))) {
if (unsync || tunsync) {
int i, j;
av_fast_malloc(&buffer, &buffer_size, tlen);
@ -280,10 +445,17 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
}
}
ffio_init_context(&pb, buffer, j, 0, NULL, NULL, NULL, NULL);
read_ttag(s, &pb, j, tag);
tlen = j;
pbx = &pb; // read from sync buffer
} else {
read_ttag(s, s->pb, tlen, tag);
pbx = s->pb; // read straight from input
}
if (tag[0] == 'T')
/* parse text tag */
read_ttag(s, pbx, tlen, tag);
else
/* parse special meta tag */
extra_func(s, pbx, tlen, tag, extra_meta);
}
else if (!tag[0]) {
if (tag[1])
@ -307,7 +479,7 @@ seek:
return;
}
void ff_id3v2_read(AVFormatContext *s, const char *magic)
void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta)
{
int len, ret;
uint8_t buf[ID3v2_HEADER_SIZE];
@ -327,7 +499,7 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic)
((buf[7] & 0x7f) << 14) |
((buf[8] & 0x7f) << 7) |
(buf[9] & 0x7f);
ff_id3v2_parse(s, len, buf[3], buf[5]);
ff_id3v2_parse(s, len, buf[3], buf[5], extra_meta);
} else {
avio_seek(s->pb, off, SEEK_SET);
}
@ -338,6 +510,30 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic)
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;
void (*free_func)(ID3v2ExtraMeta*);
while (current) {
if ((free_func = get_extra_meta_func(current->tag, 1)->free))
free_func(current->data);
next = current->next;
av_freep(&current);
current = next;
}
}
const ID3v2EMFunc ff_id3v2_extra_meta_funcs[] = {
{ "GEO", "GEOB", read_geobtag, free_geobtag },
{ NULL }
};
const AVMetadataConv ff_id3v2_34_metadata_conv[] = {
{ "TALB", "album"},
{ "TCOM", "composer"},