/* mmf input */ static int mmf_read_header(AVFormatContext *s) { MMFContext *mmf = s->priv_data; unsigned int tag; AVIOContext *pb = s->pb; AVStream *st; int64_t size; int rate, params; tag = avio_rl32(pb); if (tag != MKTAG('M', 'M', 'M', 'D')) return -1; avio_skip(pb, 4); /* file_size */ /* Skip some unused chunks that may or may not be present */ for(;; avio_skip(pb, size)) { tag = avio_rl32(pb); size = avio_rb32(pb); if(tag == MKTAG('C','N','T','I')) continue; if(tag == MKTAG('O','P','D','A')) continue; break; } /* Tag = "ATRx", where "x" = track number */ if ((tag & 0xffffff) == MKTAG('M', 'T', 'R', 0)) { av_log(s, AV_LOG_ERROR, "MIDI like format found, unsupported\n"); return -1; } if ((tag & 0xffffff) != MKTAG('A', 'T', 'R', 0)) { av_log(s, AV_LOG_ERROR, "Unsupported SMAF chunk %08x\n", tag); return -1; } avio_r8(pb); /* format type */ avio_r8(pb); /* sequence type */ params = avio_r8(pb); /* (channel << 7) | (format << 4) | rate */ rate = mmf_rate(params & 0x0f); if(rate < 0) { av_log(s, AV_LOG_ERROR, "Invalid sample rate\n"); return -1; } avio_r8(pb); /* wave base bit */ avio_r8(pb); /* time base d */ avio_r8(pb); /* time base g */ /* Skip some unused chunks that may or may not be present */ for(;; avio_skip(pb, size)) { tag = avio_rl32(pb); size = avio_rb32(pb); if(tag == MKTAG('A','t','s','q')) continue; if(tag == MKTAG('A','s','p','I')) continue; break; } /* Make sure it's followed by an Awa chunk, aka wave data */ if ((tag & 0xffffff) != MKTAG('A', 'w', 'a', 0)) { av_log(s, AV_LOG_ERROR, "Unexpected SMAF chunk %08x\n", tag); return -1; } mmf->data_size = size; st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = CODEC_ID_ADPCM_YAMAHA; st->codec->sample_rate = rate; st->codec->channels = 1; st->codec->bits_per_coded_sample = 4; st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_coded_sample; avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); return 0; }
static int open_smaf(bgav_demuxer_context_t * ctx) { int done = 0; uint8_t params; chunk_header_t ch; bgav_stream_t * s; smaf_priv_t * priv; priv = calloc(1, sizeof(*priv)); ctx->priv = priv; /* Skip MMMD chunk */ bgav_input_skip(ctx->input, 8); while(!done) { if(!read_chunk_header(ctx->input, &ch)) return 0; // dump_chunk_header(&ch); if((ch.fourcc & 0xffffff00) == BGAV_MK_FOURCC('M','T','R',0)) { bgav_log(ctx->opt, BGAV_LOG_ERROR, LOG_DOMAIN, "MIDI like files not supported"); return 0; } else if((ch.fourcc == BGAV_MK_FOURCC('C','N','T','I')) || (ch.fourcc == BGAV_MK_FOURCC('O','P','D','A'))) bgav_input_skip(ctx->input, ch.size); else if((ch.fourcc & 0xffffff00) == BGAV_MK_FOURCC('A','T','R',0)) done = 1; else { bgav_log(ctx->opt, BGAV_LOG_ERROR, LOG_DOMAIN, "Unsupported SMAF chunk (%c%c%c%c)", (ch.fourcc & 0xFF000000) >> 24, (ch.fourcc & 0x00FF0000) >> 16, (ch.fourcc & 0x0000FF00) >> 8, (ch.fourcc & 0x000000FF)); return 0; } } /* Initialize generic things */ ctx->tt = bgav_track_table_create(1); s = bgav_track_add_audio_stream(ctx->tt->cur, ctx->opt); /* Now, get the format */ bgav_input_skip(ctx->input, 1); /* format type */ bgav_input_skip(ctx->input, 1); /* sequence type */ /* (channel << 7) | (format << 4) | rate */ if(!bgav_input_read_data(ctx->input, ¶ms, 1)) return 0; s->data.audio.format.samplerate = mmf_rate(params & 0x0f); s->fourcc = BGAV_MK_FOURCC('S','M','A','F'); s->data.audio.bits_per_sample = 4; s->data.audio.format.num_channels = 1; s->data.audio.bits_per_sample = 4; s->container_bitrate = s->data.audio.bits_per_sample * s->data.audio.format.samplerate; if(s->data.audio.format.samplerate < 0) { bgav_log(ctx->opt, BGAV_LOG_ERROR, LOG_DOMAIN, "Invalid samplerate"); return 0; } bgav_input_skip(ctx->input, 1); /* wave base bit */ bgav_input_skip(ctx->input, 1); /* time base d */ bgav_input_skip(ctx->input, 1); /* time base g */ done = 0; while(!done) { if(!read_chunk_header(ctx->input, &ch)) return 0; // dump_chunk_header(&ch); if((ch.fourcc == BGAV_MK_FOURCC('A','t','s','q')) || (ch.fourcc == BGAV_MK_FOURCC('A','s','p','I'))) bgav_input_skip(ctx->input, ch.size); else if((ch.fourcc & 0xffffff00) == BGAV_MK_FOURCC('A','w','a', 0)) done = 1; else { bgav_log(ctx->opt, BGAV_LOG_ERROR, LOG_DOMAIN, "Unsupported SMAF chunk (%c%c%c%c)", (ch.fourcc & 0xFF000000) >> 24, (ch.fourcc & 0x00FF0000) >> 16, (ch.fourcc & 0x0000FF00) >> 8, (ch.fourcc & 0x000000FF)); return 0; } } priv->bytes_left = ch.size; gavl_metadata_set(&ctx->tt->cur->metadata, GAVL_META_FORMAT, "SMAF Ringtone"); return 1; }