Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * Copyright (c) 2012 Michael Niedermayer
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 *
20
 */
21
 
22
/**
23
 * @file
24
 * audio pad filter.
25
 *
26
 * Based on af_aresample.c
27
 */
28
 
29
#include "libavutil/avstring.h"
30
#include "libavutil/channel_layout.h"
31
#include "libavutil/opt.h"
32
#include "libavutil/samplefmt.h"
33
#include "libavutil/avassert.h"
34
#include "avfilter.h"
35
#include "audio.h"
36
#include "internal.h"
37
 
38
typedef struct {
39
    const AVClass *class;
40
    int64_t next_pts;
41
 
42
    int packet_size;
43
    int64_t pad_len;
44
    int64_t whole_len;
45
} APadContext;
46
 
47
#define OFFSET(x) offsetof(APadContext, x)
48
#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
49
 
50
static const AVOption apad_options[] = {
51
    { "packet_size", "set silence packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, { .i64 = 4096 }, 0, INT_MAX, A },
52
    { "pad_len",     "number of samples of silence to add",          OFFSET(pad_len),   AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, A },
53
    { "whole_len",   "target number of samples in the audio stream", OFFSET(whole_len), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, A },
54
    { NULL }
55
};
56
 
57
AVFILTER_DEFINE_CLASS(apad);
58
 
59
static av_cold int init(AVFilterContext *ctx)
60
{
61
    APadContext *apad = ctx->priv;
62
 
63
    apad->next_pts = AV_NOPTS_VALUE;
64
    if (apad->whole_len && apad->pad_len) {
65
        av_log(ctx, AV_LOG_ERROR, "Both whole and pad length are set, this is not possible\n");
66
        return AVERROR(EINVAL);
67
    }
68
 
69
    return 0;
70
}
71
 
72
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
73
{
74
    AVFilterContext *ctx = inlink->dst;
75
    APadContext *apad = ctx->priv;
76
 
77
    if (apad->whole_len)
78
        apad->whole_len -= frame->nb_samples;
79
 
80
    apad->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base);
81
    return ff_filter_frame(ctx->outputs[0], frame);
82
}
83
 
84
static int request_frame(AVFilterLink *outlink)
85
{
86
    AVFilterContext *ctx = outlink->src;
87
    APadContext *apad = ctx->priv;
88
    int ret;
89
 
90
    ret = ff_request_frame(ctx->inputs[0]);
91
 
92
    if (ret == AVERROR_EOF && !ctx->is_disabled) {
93
        int n_out = apad->packet_size;
94
        AVFrame *outsamplesref;
95
 
96
        if (apad->whole_len > 0) {
97
            apad->pad_len = apad->whole_len;
98
            apad->whole_len = 0;
99
        }
100
        if (apad->pad_len > 0) {
101
            n_out = FFMIN(n_out, apad->pad_len);
102
            apad->pad_len -= n_out;
103
        }
104
 
105
        if(!n_out)
106
            return AVERROR_EOF;
107
 
108
        outsamplesref = ff_get_audio_buffer(outlink, n_out);
109
        if (!outsamplesref)
110
            return AVERROR(ENOMEM);
111
 
112
        av_assert0(outsamplesref->sample_rate == outlink->sample_rate);
113
        av_assert0(outsamplesref->nb_samples  == n_out);
114
 
115
        av_samples_set_silence(outsamplesref->extended_data, 0,
116
                               n_out,
117
                               av_frame_get_channels(outsamplesref),
118
                               outsamplesref->format);
119
 
120
        outsamplesref->pts = apad->next_pts;
121
        if (apad->next_pts != AV_NOPTS_VALUE)
122
            apad->next_pts += av_rescale_q(n_out, (AVRational){1, outlink->sample_rate}, outlink->time_base);
123
 
124
        return ff_filter_frame(outlink, outsamplesref);
125
    }
126
    return ret;
127
}
128
 
129
static const AVFilterPad apad_inputs[] = {
130
    {
131
        .name         = "default",
132
        .type         = AVMEDIA_TYPE_AUDIO,
133
        .filter_frame = filter_frame,
134
    },
135
    { NULL }
136
};
137
 
138
static const AVFilterPad apad_outputs[] = {
139
    {
140
        .name          = "default",
141
        .request_frame = request_frame,
142
        .type          = AVMEDIA_TYPE_AUDIO,
143
    },
144
    { NULL }
145
};
146
 
147
AVFilter avfilter_af_apad = {
148
    .name          = "apad",
149
    .description   = NULL_IF_CONFIG_SMALL("Pad audio with silence."),
150
    .init          = init,
151
    .priv_size     = sizeof(APadContext),
152
    .inputs        = apad_inputs,
153
    .outputs       = apad_outputs,
154
    .priv_class    = &apad_class,
155
    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
156
};