/** * Parse an ID3v1 tag * * @param buf ID3v1_TAG_SIZE long buffer containing the tag */ static int parse_tag(AVFormatContext *s, const uint8_t *buf) { char str[5]; int genre; if (!(buf[0] == 'T' && buf[1] == 'A' && buf[2] == 'G')) { return -1; } get_string(s, "title", buf + 3, 30); get_string(s, "artist", buf + 33, 30); get_string(s, "album", buf + 63, 30); get_string(s, "date", buf + 93, 4); get_string(s, "comment", buf + 97, 30); if (buf[125] == 0 && buf[126] != 0) { snprintf(str, sizeof(str), "%d", buf[126]); av_metadata_set2(&s->metadata, "track", str, 0); } genre = buf[127]; if (genre <= ID3v1_GENRE_MAX) { av_metadata_set2(&s->metadata, "genre", ff_id3v1_genre_str[genre], 0); } return 0; }
static int read_tag(uint8_t *line, AVMetadata **m) { uint8_t *key, *value, *p = line; /* find first not escaped '=' */ while (1) { if (*p == '=') break; else if (*p == '\\') p++; if (*p++) continue; return 0; } if (!(key = unescape(line, p - line))) return AVERROR(ENOMEM); if (!(value = unescape(p + 1, strlen(p + 1)))) { av_free(key); return AVERROR(ENOMEM); } av_metadata_set2(m, key, value, AV_METADATA_DONT_STRDUP_KEY | AV_METADATA_DONT_STRDUP_VAL); return 0; }
static int ape_tag_read_field(AVFormatContext *s) { AVIOContext *pb = s->pb; uint8_t key[1024], *value; uint32_t size, flags; int i, c; size = avio_rl32(pb); /* field size */ flags = avio_rl32(pb); /* field flags */ for (i = 0; i < sizeof(key) - 1; i++) { c = avio_r8(pb); if (c < 0x20 || c > 0x7E) break; else key[i] = c; } key[i] = 0; if (c != 0) { av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key); return -1; } if (size >= UINT_MAX) return -1; value = av_malloc(size+1); if (!value) return AVERROR(ENOMEM); avio_read(pb, value, size); value[size] = 0; av_metadata_set2(&s->metadata, key, value, AV_METADATA_DONT_STRDUP_VAL); return 0; }
void metadata_conv(AVMetadata **pm, const AVMetadataConv *d_conv, const AVMetadataConv *s_conv) { /* TODO: use binary search to look up the two conversion tables if the tables are getting big enough that it would matter speed wise */ const AVMetadataConv *sc, *dc; AVMetadataTag *mtag = NULL; AVMetadata *dst = NULL; const char *key; while((mtag=av_metadata_get(*pm, "", mtag, AV_METADATA_IGNORE_SUFFIX))) { key = mtag->key; if (s_conv != d_conv) { if (s_conv) for (sc=s_conv; sc->native; sc++) if (!strcasecmp(key, sc->native)) { key = sc->generic; break; } if (d_conv) for (dc=d_conv; dc->native; dc++) if (!strcasecmp(key, dc->generic)) { key = dc->native; break; } } av_metadata_set2(&dst, key, mtag->value, 0); } av_metadata_free(pm); *pm = dst; }
void av_metadata_copy(AVMetadata **dst, AVMetadata *src, int flags) { AVMetadataTag *t = NULL; while ((t = av_metadata_get(src, "", t, AV_METADATA_IGNORE_SUFFIX))) av_metadata_set2(dst, t->key, t->value, flags); }
static int r3d_read_red1(AVFormatContext *s) { AVStream *st = av_new_stream(s, 0); char filename[258]; int tmp, tmp2; if (!st) return AVERROR(ENOMEM); st->codec->codec_type = AVMEDIA_TYPE_VIDEO; st->codec->codec_id = CODEC_ID_JPEG2000; tmp = avio_r8(s->pb); // major version tmp2 = avio_r8(s->pb); // minor version av_dlog(s, "version %d.%d\n", tmp, tmp2); tmp = avio_rb16(s->pb); // unknown av_dlog(s, "unknown1 %d\n", tmp); tmp = avio_rb32(s->pb); av_set_pts_info(st, 32, 1, tmp); tmp = avio_rb32(s->pb); // filenum av_dlog(s, "filenum %d\n", tmp); avio_skip(s->pb, 32); // unknown st->codec->width = avio_rb32(s->pb); st->codec->height = avio_rb32(s->pb); tmp = avio_rb16(s->pb); // unknown av_dlog(s, "unknown2 %d\n", tmp); st->codec->time_base.den = avio_rb16(s->pb); st->codec->time_base.num = avio_rb16(s->pb); tmp = avio_r8(s->pb); // audio channels av_dlog(s, "audio channels %d\n", tmp); if (tmp > 0) { AVStream *ast = av_new_stream(s, 1); if (!ast) return AVERROR(ENOMEM); ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; ast->codec->codec_id = CODEC_ID_PCM_S32BE; ast->codec->channels = tmp; av_set_pts_info(ast, 32, 1, st->time_base.den); } avio_read(s->pb, filename, 257); filename[sizeof(filename)-1] = 0; av_metadata_set2(&st->metadata, "filename", filename, 0); av_dlog(s, "filename %s\n", filename); av_dlog(s, "resolution %dx%d\n", st->codec->width, st->codec->height); av_dlog(s, "timescale %d\n", st->time_base.den); av_dlog(s, "frame rate %d/%d\n", st->codec->time_base.num, st->codec->time_base.den); return 0; }
/** Read information chunk */ static void read_info_chunk(AVFormatContext *s, int64_t size) { ByteIOContext *pb = s->pb; unsigned int i; unsigned int nb_entries = get_be32(pb); for (i = 0; i < nb_entries; i++) { char key[32]; char value[1024]; get_strz(pb, key, sizeof(key)); get_strz(pb, value, sizeof(value)); av_metadata_set2(&s->metadata, key, value, 0); } }
/* Metadata string read */ static void get_meta(AVFormatContext *s, const char *key, int size) { uint8_t *str = av_malloc(size+1); int res; if (!str) { avio_skip(s->pb, size); return; } res = avio_read(s->pb, str, size); if (res < 0) return; str[res] = 0; av_metadata_set2(&s->metadata, key, str, AV_METADATA_DONT_STRDUP_VAL); }
/* Metadata string read */ static int get_metadata(AVFormatContext *s, const char *const tag, const unsigned data_size) { uint8_t *buf = ((data_size + 1) == 0) ? NULL : av_malloc(data_size + 1); if (!buf) return AVERROR(ENOMEM); if (avio_read(s->pb, buf, data_size) < 0) { av_free(buf); return AVERROR(EIO); } buf[data_size] = 0; av_metadata_set2(&s->metadata, tag, buf, AV_METADATA_DONT_STRDUP_VAL); return 0; }
static void get_string(AVFormatContext *s, const char *key, const uint8_t *buf, int buf_size) { int i, c; char *q, str[512]; q = str; for(i = 0; i < buf_size; i++) { c = buf[i]; if (c == '\0') break; if ((q - str) >= sizeof(str) - 1) break; *q++ = c; } *q = '\0'; if (*str) av_metadata_set2(&s->metadata, key, str, 0); }
int av_metadata_set(AVMetadata **pm, const char *key, const char *value) { return av_metadata_set2(pm, key, value, 0); }
static int applehttp_read_header(AVFormatContext *s, AVFormatParameters *ap) { AppleHTTPContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) goto fail; if (c->n_variants == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } /* If the playlist only contained variants, parse each individual * variant playlist. */ if (c->n_variants > 1 || c->variants[0]->n_segments == 0) { for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) goto fail; } } if (c->variants[0]->n_segments == 0) { av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } /* If this isn't a live stream, calculate the total duration of the * stream. */ if (c->variants[0]->finished) { int64_t duration = 0; for (i = 0; i < c->variants[0]->n_segments; i++) duration += c->variants[0]->segments[i]->duration; s->duration = duration * AV_TIME_BASE; } /* Open the demuxer for each variant */ for (i = 0; i < c->n_variants; i++) { struct variant *v = c->variants[i]; AVInputFormat *in_fmt = NULL; char bitrate_str[20]; if (v->n_segments == 0) continue; v->index = i; v->needed = 1; v->parent = s; /* If this is a live stream with more than 3 segments, start at the * third last segment. */ v->cur_seq_no = v->start_seq_no; if (!v->finished && v->n_segments > 3) v->cur_seq_no = v->start_seq_no + v->n_segments - 3; v->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); ffio_init_context(&v->pb, v->read_buffer, INITIAL_BUFFER_SIZE, 0, v, read_data, NULL, NULL); v->pb.seekable = 0; ret = av_probe_input_buffer(&v->pb, &in_fmt, v->segments[0]->url, NULL, 0, 0); if (ret < 0) goto fail; ret = av_open_input_stream(&v->ctx, &v->pb, v->segments[0]->url, in_fmt, NULL); if (ret < 0) goto fail; v->stream_offset = stream_offset; snprintf(bitrate_str, sizeof(bitrate_str), "%d", v->bandwidth); /* Create new AVStreams for each stream in this variant */ for (j = 0; j < v->ctx->nb_streams; j++) { AVStream *st = av_new_stream(s, i); if (!st) { ret = AVERROR(ENOMEM); goto fail; } avcodec_copy_context(st->codec, v->ctx->streams[j]->codec); av_metadata_set2(&st->metadata, "variant_bitrate", bitrate_str, 0); } stream_offset += v->ctx->nb_streams; } c->first_packet = 1; return 0; fail: free_variant_list(c); return ret; }
static int iff_read_header(AVFormatContext *s, AVFormatParameters *ap) { IffDemuxContext *iff = s->priv_data; ByteIOContext *pb = s->pb; AVStream *st; uint32_t chunk_id, data_size; int padding, done = 0; int compression = -1; char *buf; st = av_new_stream(s, 0); if (!st) return AVERROR(ENOMEM); st->codec->channels = 1; url_fskip(pb, 8); // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content st->codec->codec_tag = get_le32(pb); while(!done && !url_feof(pb)) { chunk_id = get_le32(pb); data_size = get_be32(pb); padding = data_size & 1; switch(chunk_id) { case ID_VHDR: st->codec->codec_type = CODEC_TYPE_AUDIO; url_fskip(pb, 12); st->codec->sample_rate = get_be16(pb); url_fskip(pb, 1); compression = get_byte(pb); url_fskip(pb, 4); break; case ID_BODY: iff->body_size = data_size; done = 1; break; case ID_CHAN: st->codec->channels = (get_be32(pb) < 6) ? 1 : 2; break; case ID_CMAP: st->codec->extradata_size = data_size; st->codec->extradata = av_malloc(data_size); if (!st->codec->extradata) return AVERROR(ENOMEM); if (get_buffer(pb, st->codec->extradata, data_size) < 0) return AVERROR(EIO); break; case ID_BMHD: st->codec->codec_type = CODEC_TYPE_VIDEO; st->codec->width = get_be16(pb); st->codec->height = get_be16(pb); url_fskip(pb, 4); // x, y offset st->codec->bits_per_coded_sample = get_byte(pb); url_fskip(pb, 1); // masking compression = get_byte(pb); url_fskip(pb, 3); // paddding, transparent st->sample_aspect_ratio.num = get_byte(pb); st->sample_aspect_ratio.den = get_byte(pb); url_fskip(pb, 4); // source page width, height break; case ID_ANNO: buf = av_malloc(data_size + 1); if (!buf) break; get_buffer(pb, buf, data_size); buf[data_size] = 0; av_metadata_set2(&s->metadata, "comment", buf, AV_METADATA_DONT_STRDUP_VAL); break; default: url_fseek(pb, data_size + padding, SEEK_CUR); break; } } switch(st->codec->codec_type) { case CODEC_TYPE_AUDIO: av_set_pts_info(st, 32, 1, st->codec->sample_rate); switch(compression) { case COMP_NONE: st->codec->codec_id = CODEC_ID_PCM_S8; break; case COMP_FIB: st->codec->codec_id = CODEC_ID_8SVX_FIB; break; case COMP_EXP: st->codec->codec_id = CODEC_ID_8SVX_EXP; break; default: av_log(s, AV_LOG_ERROR, "iff: unknown compression method\n"); return -1; } st->codec->bits_per_coded_sample = 8; st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample; st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; break; case CODEC_TYPE_VIDEO: switch (compression) { case BITMAP_RAW: if (st->codec->codec_tag == ID_ILBM) { st->codec->codec_id = CODEC_ID_IFF_ILBM; } else { st->codec->codec_id = CODEC_ID_RAWVIDEO; st->codec->pix_fmt = PIX_FMT_PAL8; st->codec->codec_tag = 0; } break; case BITMAP_BYTERUN1: st->codec->codec_id = CODEC_ID_IFF_BYTERUN1; break; default: av_log(s, AV_LOG_ERROR, "unknown compression method\n"); return AVERROR_INVALIDDATA; } break; default: return -1; } return 0; }
static int rpl_read_header(AVFormatContext *s, AVFormatParameters *ap) { ByteIOContext *pb = s->pb; RPLContext *rpl = s->priv_data; AVStream *vst = NULL, *ast = NULL; int total_audio_size; int error = 0; uint32_t i; int32_t audio_format, chunk_catalog_offset, number_of_chunks; AVRational fps; char line[RPL_LINE_LENGTH]; // The header for RPL/ARMovie files is 21 lines of text // containing the various header fields. The fields are always // in the same order, and other text besides the first // number usually isn't important. // (The spec says that there exists some significance // for the text in a few cases; samples needed.) error |= read_line(pb, line, sizeof(line)); // ARMovie error |= read_line(pb, line, sizeof(line)); // movie name av_metadata_set2(&s->metadata, "title" , line, 0); error |= read_line(pb, line, sizeof(line)); // date/copyright av_metadata_set2(&s->metadata, "copyright", line, 0); error |= read_line(pb, line, sizeof(line)); // author and other av_metadata_set2(&s->metadata, "author" , line, 0); // video headers vst = av_new_stream(s, 0); if (!vst) return AVERROR(ENOMEM); vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; vst->codec->codec_tag = read_line_and_int(pb, &error); // video format vst->codec->width = read_line_and_int(pb, &error); // video width vst->codec->height = read_line_and_int(pb, &error); // video height vst->codec->bits_per_coded_sample = read_line_and_int(pb, &error); // video bits per sample error |= read_line(pb, line, sizeof(line)); // video frames per second fps = read_fps(line, &error); av_set_pts_info(vst, 32, fps.den, fps.num); // Figure out the video codec switch (vst->codec->codec_tag) { #if 0 case 122: vst->codec->codec_id = CODEC_ID_ESCAPE122; break; #endif case 124: vst->codec->codec_id = CODEC_ID_ESCAPE124; // The header is wrong here, at least sometimes vst->codec->bits_per_coded_sample = 16; break; #if 0 case 130: vst->codec->codec_id = CODEC_ID_ESCAPE130; break; #endif default: av_log(s, AV_LOG_WARNING, "RPL video format %i not supported yet!\n", vst->codec->codec_tag); vst->codec->codec_id = CODEC_ID_NONE; } // Audio headers // ARMovie supports multiple audio tracks; I don't have any // samples, though. This code will ignore additional tracks. audio_format = read_line_and_int(pb, &error); // audio format ID if (audio_format) { ast = av_new_stream(s, 0); if (!ast) return AVERROR(ENOMEM); ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; ast->codec->codec_tag = audio_format; ast->codec->sample_rate = read_line_and_int(pb, &error); // audio bitrate ast->codec->channels = read_line_and_int(pb, &error); // number of audio channels ast->codec->bits_per_coded_sample = read_line_and_int(pb, &error); // audio bits per sample // At least one sample uses 0 for ADPCM, which is really 4 bits // per sample. if (ast->codec->bits_per_coded_sample == 0) ast->codec->bits_per_coded_sample = 4; ast->codec->bit_rate = ast->codec->sample_rate * ast->codec->bits_per_coded_sample * ast->codec->channels; ast->codec->codec_id = CODEC_ID_NONE; switch (audio_format) { case 1: if (ast->codec->bits_per_coded_sample == 16) { // 16-bit audio is always signed ast->codec->codec_id = CODEC_ID_PCM_S16LE; break; } // There are some other formats listed as legal per the spec; // samples needed. break; case 101: if (ast->codec->bits_per_coded_sample == 8) { // The samples with this kind of audio that I have // are all unsigned. ast->codec->codec_id = CODEC_ID_PCM_U8; break; } else if (ast->codec->bits_per_coded_sample == 4) { ast->codec->codec_id = CODEC_ID_ADPCM_IMA_EA_SEAD; break; } break; } if (ast->codec->codec_id == CODEC_ID_NONE) { av_log(s, AV_LOG_WARNING, "RPL audio format %i not supported yet!\n", audio_format); } av_set_pts_info(ast, 32, 1, ast->codec->bit_rate); } else { for (i = 0; i < 3; i++) error |= read_line(pb, line, sizeof(line)); } rpl->frames_per_chunk = read_line_and_int(pb, &error); // video frames per chunk if (rpl->frames_per_chunk > 1 && vst->codec->codec_tag != 124) av_log(s, AV_LOG_WARNING, "Don't know how to split frames for video format %i. " "Video stream will be broken!\n", vst->codec->codec_tag); number_of_chunks = read_line_and_int(pb, &error); // number of chunks in the file // The number in the header is actually the index of the last chunk. number_of_chunks++; error |= read_line(pb, line, sizeof(line)); // "even" chunk size in bytes error |= read_line(pb, line, sizeof(line)); // "odd" chunk size in bytes chunk_catalog_offset = // offset of the "chunk catalog" read_line_and_int(pb, &error); // (file index) error |= read_line(pb, line, sizeof(line)); // offset to "helpful" sprite error |= read_line(pb, line, sizeof(line)); // size of "helpful" sprite error |= read_line(pb, line, sizeof(line)); // offset to key frame list // Read the index url_fseek(pb, chunk_catalog_offset, SEEK_SET); total_audio_size = 0; for (i = 0; i < number_of_chunks; i++) { int64_t offset, video_size, audio_size; error |= read_line(pb, line, sizeof(line)); if (3 != sscanf(line, "%"PRId64" , %"PRId64" ; %"PRId64, &offset, &video_size, &audio_size)) error = -1; av_add_index_entry(vst, offset, i * rpl->frames_per_chunk, video_size, rpl->frames_per_chunk, 0); if (ast) av_add_index_entry(ast, offset + video_size, total_audio_size, audio_size, audio_size * 8, 0); total_audio_size += audio_size * 8; } if (error) return AVERROR(EIO); return 0; }
static int nsv_parse_NSVf_header(AVFormatContext *s, AVFormatParameters *ap) { NSVContext *nsv = s->priv_data; AVIOContext *pb = s->pb; unsigned int file_size, size; int64_t duration; int strings_size; int table_entries; int table_entries_used; av_dlog(s, "%s()\n", __FUNCTION__); nsv->state = NSV_UNSYNC; /* in case we fail */ size = avio_rl32(pb); if (size < 28) return -1; nsv->NSVf_end = size; //s->file_size = (uint32_t)avio_rl32(pb); file_size = (uint32_t)avio_rl32(pb); av_dlog(s, "NSV NSVf chunk_size %u\n", size); av_dlog(s, "NSV NSVf file_size %u\n", file_size); nsv->duration = duration = avio_rl32(pb); /* in ms */ av_dlog(s, "NSV NSVf duration %"PRId64" ms\n", duration); // XXX: store it in AVStreams strings_size = avio_rl32(pb); table_entries = avio_rl32(pb); table_entries_used = avio_rl32(pb); av_dlog(s, "NSV NSVf info-strings size: %d, table entries: %d, bis %d\n", strings_size, table_entries, table_entries_used); if (pb->eof_reached) return -1; av_dlog(s, "NSV got header; filepos %"PRId64"\n", avio_tell(pb)); if (strings_size > 0) { char *strings; /* last byte will be '\0' to play safe with str*() */ char *p, *endp; char *token, *value; char quote; p = strings = av_mallocz(strings_size + 1); endp = strings + strings_size; avio_read(pb, strings, strings_size); while (p < endp) { while (*p == ' ') p++; /* strip out spaces */ if (p >= endp-2) break; token = p; p = strchr(p, '='); if (!p || p >= endp-2) break; *p++ = '\0'; quote = *p++; value = p; p = strchr(p, quote); if (!p || p >= endp) break; *p++ = '\0'; av_dlog(s, "NSV NSVf INFO: %s='%s'\n", token, value); av_metadata_set2(&s->metadata, token, value, 0); } av_free(strings); } if (pb->eof_reached) return -1; av_dlog(s, "NSV got infos; filepos %"PRId64"\n", avio_tell(pb)); if (table_entries_used > 0) { int i; nsv->index_entries = table_entries_used; if((unsigned)table_entries_used >= UINT_MAX / sizeof(uint32_t)) return -1; nsv->nsvs_file_offset = av_malloc((unsigned)table_entries_used * sizeof(uint32_t)); for(i=0;i<table_entries_used;i++) nsv->nsvs_file_offset[i] = avio_rl32(pb) + size; if(table_entries > table_entries_used && avio_rl32(pb) == MKTAG('T','O','C','2')) { nsv->nsvs_timestamps = av_malloc((unsigned)table_entries_used*sizeof(uint32_t)); for(i=0;i<table_entries_used;i++) { nsv->nsvs_timestamps[i] = avio_rl32(pb); } } } av_dlog(s, "NSV got index; filepos %"PRId64"\n", avio_tell(pb)); #ifdef DEBUG_DUMP_INDEX #define V(v) ((v<0x20 || v > 127)?'.':v) /* dump index */ av_dlog(s, "NSV %d INDEX ENTRIES:\n", table_entries); av_dlog(s, "NSV [dataoffset][fileoffset]\n", table_entries); for (i = 0; i < table_entries; i++) { unsigned char b[8]; avio_seek(pb, size + nsv->nsvs_file_offset[i], SEEK_SET); avio_read(pb, b, 8); av_dlog(s, "NSV [0x%08lx][0x%08lx]: %02x %02x %02x %02x %02x %02x %02x %02x" "%c%c%c%c%c%c%c%c\n", nsv->nsvs_file_offset[i], size + nsv->nsvs_file_offset[i], b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], V(b[0]), V(b[1]), V(b[2]), V(b[3]), V(b[4]), V(b[5]), V(b[6]), V(b[7]) ); } //avio_seek(pb, size, SEEK_SET); /* go back to end of header */ #undef V #endif avio_seek(pb, nsv->base_offset + size, SEEK_SET); /* required for dumbdriving-271.nsv (2 extra bytes) */ if (pb->eof_reached) return -1; nsv->state = NSV_HAS_READ_NSVF; return 0; }