1/* 2 * Audio Frame Queue 3 * Copyright (c) 2012 Justin Ruggles 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "libavutil/attributes.h" 23#include "libavutil/common.h" 24#include "audio_frame_queue.h" 25#include "internal.h" 26#include "libavutil/avassert.h" 27 28av_cold void ff_af_queue_init(AVCodecContext *avctx, AudioFrameQueue *afq) 29{ 30 afq->avctx = avctx; 31 afq->remaining_delay = avctx->initial_padding; 32 afq->remaining_samples = avctx->initial_padding; 33 afq->frame_count = 0; 34} 35 36void ff_af_queue_close(AudioFrameQueue *afq) 37{ 38 if(afq->frame_count) 39 av_log(afq->avctx, AV_LOG_WARNING, "%d frames left in the queue on closing\n", afq->frame_count); 40 av_freep(&afq->frames); 41 memset(afq, 0, sizeof(*afq)); 42} 43 44int ff_af_queue_add(AudioFrameQueue *afq, const AVFrame *f) 45{ 46 AudioFrame *new = av_fast_realloc(afq->frames, &afq->frame_alloc, sizeof(*afq->frames)*(afq->frame_count+1)); 47 if(!new) 48 return AVERROR(ENOMEM); 49 afq->frames = new; 50 new += afq->frame_count; 51 52 /* get frame parameters */ 53 new->duration = f->nb_samples; 54 new->duration += afq->remaining_delay; 55 if (f->pts != AV_NOPTS_VALUE) { 56 new->pts = av_rescale_q(f->pts, 57 afq->avctx->time_base, 58 (AVRational){ 1, afq->avctx->sample_rate }); 59 new->pts -= afq->remaining_delay; 60 if(afq->frame_count && new[-1].pts >= new->pts) 61 av_log(afq->avctx, AV_LOG_WARNING, "Queue input is backward in time\n"); 62 } else { 63 new->pts = AV_NOPTS_VALUE; 64 } 65 afq->remaining_delay = 0; 66 67 /* add frame sample count */ 68 afq->remaining_samples += f->nb_samples; 69 70 afq->frame_count++; 71 72 return 0; 73} 74 75void ff_af_queue_remove(AudioFrameQueue *afq, int nb_samples, int64_t *pts, 76 int64_t *duration) 77{ 78 int64_t out_pts = AV_NOPTS_VALUE; 79 int removed_samples = 0; 80 int i; 81 82 if (afq->frame_count || afq->frame_alloc) { 83 if (afq->frames->pts != AV_NOPTS_VALUE) 84 out_pts = afq->frames->pts; 85 } 86 if(!afq->frame_count) 87 av_log(afq->avctx, AV_LOG_WARNING, "Trying to remove %d samples, but the queue is empty\n", nb_samples); 88 if (pts) 89 *pts = ff_samples_to_time_base(afq->avctx, out_pts); 90 91 for(i=0; nb_samples && i<afq->frame_count; i++){ 92 int n= FFMIN(afq->frames[i].duration, nb_samples); 93 afq->frames[i].duration -= n; 94 nb_samples -= n; 95 removed_samples += n; 96 if(afq->frames[i].pts != AV_NOPTS_VALUE) 97 afq->frames[i].pts += n; 98 } 99 afq->remaining_samples -= removed_samples; 100 i -= i && afq->frames[i-1].duration; 101 memmove(afq->frames, afq->frames + i, sizeof(*afq->frames) * (afq->frame_count - i)); 102 afq->frame_count -= i; 103 104 if(nb_samples){ 105 av_assert0(!afq->frame_count); 106 av_assert0(afq->remaining_samples == afq->remaining_delay); 107 if(afq->frames && afq->frames[0].pts != AV_NOPTS_VALUE) 108 afq->frames[0].pts += nb_samples; 109 av_log(afq->avctx, AV_LOG_DEBUG, "Trying to remove %d more samples than there are in the queue\n", nb_samples); 110 } 111 if (duration) 112 *duration = ff_samples_to_time_base(afq->avctx, removed_samples); 113} 114