Merge remote-tracking branch 'qatar/master'
[ffmpeg.git] / libavcodec / audio_frame_queue.c
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 "audio_frame_queue.h"
23 #include "internal.h"
24 #include "libavutil/avassert.h"
25
26 void ff_af_queue_init(AVCodecContext *avctx, AudioFrameQueue *afq)
27 {
28     afq->avctx = avctx;
29     afq->remaining_delay   = avctx->delay;
30     afq->remaining_samples = avctx->delay;
31     afq->frame_count       = 0;
32 }
33
34 void ff_af_queue_close(AudioFrameQueue *afq)
35 {
36     if(afq->frame_count)
37         av_log(afq->avctx, AV_LOG_WARNING, "%d frames left in que on closing\n", afq->frame_count);
38     av_freep(&afq->frames);
39     memset(afq, 0, sizeof(*afq));
40 }
41
42 int ff_af_queue_add(AudioFrameQueue *afq, const AVFrame *f)
43 {
44     AudioFrame *new = av_fast_realloc(afq->frames, &afq->frame_alloc, sizeof(*afq->frames)*(afq->frame_count+1));
45     if(!new)
46         return AVERROR(ENOMEM);
47     afq->frames = new;
48     new += afq->frame_count;
49
50     /* get frame parameters */
51     new->duration = f->nb_samples;
52     new->duration += afq->remaining_delay;
53     if (f->pts != AV_NOPTS_VALUE) {
54         new->pts = av_rescale_q(f->pts,
55                                       afq->avctx->time_base,
56                                       (AVRational){ 1, afq->avctx->sample_rate });
57         new->pts -= afq->remaining_delay;
58         if(afq->frame_count && new[-1].pts >= new->pts)
59             av_log(afq->avctx, AV_LOG_WARNING, "Que input is backward in time\n");
60     } else {
61         new->pts = AV_NOPTS_VALUE;
62     }
63     afq->remaining_delay = 0;
64
65     /* add frame sample count */
66     afq->remaining_samples += f->nb_samples;
67
68     afq->frame_count++;
69
70     return 0;
71 }
72
73 void ff_af_queue_remove(AudioFrameQueue *afq, int nb_samples, int64_t *pts,
74                         int *duration)
75 {
76     int64_t out_pts = AV_NOPTS_VALUE;
77     int removed_samples = 0;
78     int i;
79
80     if (afq->frame_count || afq->frame_alloc) {
81         if (afq->frames->pts != AV_NOPTS_VALUE)
82             out_pts = afq->frames->pts;
83     }
84     if(!afq->frame_count)
85         av_log(afq->avctx, AV_LOG_WARNING, "Trying to remove %d samples, but que empty\n", nb_samples);
86     if (pts)
87         *pts = ff_samples_to_time_base(afq->avctx, out_pts);
88
89     for(i=0; nb_samples && i<afq->frame_count; i++){
90         int n= FFMIN(afq->frames[i].duration, nb_samples);
91         afq->frames[i].duration -= n;
92         nb_samples              -= n;
93         removed_samples         += n;
94         if(afq->frames[i].pts != AV_NOPTS_VALUE)
95             afq->frames[i].pts      += n;
96     }
97     i -= i && afq->frames[i-1].duration;
98     memmove(afq->frames, afq->frames + i, sizeof(*afq->frames) * (afq->frame_count - i));
99     afq->frame_count -= i;
100
101     if(nb_samples){
102         av_assert0(!afq->frame_count);
103         if(afq->frames && afq->frames[0].pts != AV_NOPTS_VALUE)
104             afq->frames[0].pts += nb_samples;
105         av_log(afq->avctx, AV_LOG_DEBUG, "Trying to remove %d more samples than are in the que\n", nb_samples);
106     }
107     if (duration)
108         *duration = ff_samples_to_time_base(afq->avctx, removed_samples);
109 }
110