yading@11: /* yading@11: * Audio Interleaving functions yading@11: * yading@11: * Copyright (c) 2009 Baptiste Coudurier yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: #include "libavutil/fifo.h" yading@11: #include "libavutil/mathematics.h" yading@11: #include "avformat.h" yading@11: #include "audiointerleave.h" yading@11: #include "internal.h" yading@11: yading@11: void ff_audio_interleave_close(AVFormatContext *s) yading@11: { yading@11: int i; yading@11: for (i = 0; i < s->nb_streams; i++) { yading@11: AVStream *st = s->streams[i]; yading@11: AudioInterleaveContext *aic = st->priv_data; yading@11: yading@11: if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) yading@11: av_fifo_free(aic->fifo); yading@11: } yading@11: } yading@11: yading@11: int ff_audio_interleave_init(AVFormatContext *s, yading@11: const int *samples_per_frame, yading@11: AVRational time_base) yading@11: { yading@11: int i; yading@11: yading@11: if (!samples_per_frame) yading@11: return -1; yading@11: yading@11: if (!time_base.num) { yading@11: av_log(s, AV_LOG_ERROR, "timebase not set for audio interleave\n"); yading@11: return -1; yading@11: } yading@11: for (i = 0; i < s->nb_streams; i++) { yading@11: AVStream *st = s->streams[i]; yading@11: AudioInterleaveContext *aic = st->priv_data; yading@11: yading@11: if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { yading@11: aic->sample_size = (st->codec->channels * yading@11: av_get_bits_per_sample(st->codec->codec_id)) / 8; yading@11: if (!aic->sample_size) { yading@11: av_log(s, AV_LOG_ERROR, "could not compute sample size\n"); yading@11: return -1; yading@11: } yading@11: aic->samples_per_frame = samples_per_frame; yading@11: aic->samples = aic->samples_per_frame; yading@11: aic->time_base = time_base; yading@11: yading@11: aic->fifo_size = 100* *aic->samples; yading@11: aic->fifo= av_fifo_alloc(100 * *aic->samples); yading@11: } yading@11: } yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: static int ff_interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt, yading@11: int stream_index, int flush) yading@11: { yading@11: AVStream *st = s->streams[stream_index]; yading@11: AudioInterleaveContext *aic = st->priv_data; yading@11: yading@11: int size = FFMIN(av_fifo_size(aic->fifo), *aic->samples * aic->sample_size); yading@11: if (!size || (!flush && size == av_fifo_size(aic->fifo))) yading@11: return 0; yading@11: yading@11: if (av_new_packet(pkt, size) < 0) yading@11: return AVERROR(ENOMEM); yading@11: av_fifo_generic_read(aic->fifo, pkt->data, size, NULL); yading@11: yading@11: pkt->dts = pkt->pts = aic->dts; yading@11: pkt->duration = av_rescale_q(*aic->samples, st->time_base, aic->time_base); yading@11: pkt->stream_index = stream_index; yading@11: aic->dts += pkt->duration; yading@11: yading@11: aic->samples++; yading@11: if (!*aic->samples) yading@11: aic->samples = aic->samples_per_frame; yading@11: yading@11: return size; yading@11: } yading@11: yading@11: int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush, yading@11: int (*get_packet)(AVFormatContext *, AVPacket *, AVPacket *, int), yading@11: int (*compare_ts)(AVFormatContext *, AVPacket *, AVPacket *)) yading@11: { yading@11: int i; yading@11: yading@11: if (pkt) { yading@11: AVStream *st = s->streams[pkt->stream_index]; yading@11: AudioInterleaveContext *aic = st->priv_data; yading@11: if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { yading@11: unsigned new_size = av_fifo_size(aic->fifo) + pkt->size; yading@11: if (new_size > aic->fifo_size) { yading@11: if (av_fifo_realloc2(aic->fifo, new_size) < 0) yading@11: return -1; yading@11: aic->fifo_size = new_size; yading@11: } yading@11: av_fifo_generic_write(aic->fifo, pkt->data, pkt->size, NULL); yading@11: } else { yading@11: int ret; yading@11: // rewrite pts and dts to be decoded time line position yading@11: pkt->pts = pkt->dts = aic->dts; yading@11: aic->dts += pkt->duration; yading@11: ret = ff_interleave_add_packet(s, pkt, compare_ts); yading@11: if (ret < 0) yading@11: return ret; yading@11: } yading@11: pkt = NULL; yading@11: } yading@11: yading@11: for (i = 0; i < s->nb_streams; i++) { yading@11: AVStream *st = s->streams[i]; yading@11: if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { yading@11: AVPacket new_pkt; yading@11: int ret; yading@11: while ((ret = ff_interleave_new_audio_packet(s, &new_pkt, i, flush)) > 0) { yading@11: ret = ff_interleave_add_packet(s, &new_pkt, compare_ts); yading@11: if (ret < 0) yading@11: return ret; yading@11: } yading@11: if (ret < 0) yading@11: return ret; yading@11: } yading@11: } yading@11: yading@11: return get_packet(s, out, NULL, flush); yading@11: }