avcodec/bitstream_filter: Fix initializing options from the argument string
[ffmpeg.git] / libavcodec / bitstream_filter.c
1 /*
2  * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
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 #include <string.h>
22
23 #include "avcodec.h"
24 #include "libavutil/atomic.h"
25 #include "libavutil/internal.h"
26 #include "libavutil/mem.h"
27 #include "libavutil/opt.h"
28
29 #if FF_API_OLD_BSF
30 FF_DISABLE_DEPRECATION_WARNINGS
31
32 AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f)
33 {
34     const AVBitStreamFilter *filter = NULL;
35     void *opaque = NULL;
36
37     while (filter != f)
38         filter = av_bsf_next(&opaque);
39
40     return av_bsf_next(&opaque);
41 }
42
43 void av_register_bitstream_filter(AVBitStreamFilter *bsf)
44 {
45 }
46
47 typedef struct BSFCompatContext {
48     AVBSFContext *ctx;
49     int extradata_updated;
50 } BSFCompatContext;
51
52 AVBitStreamFilterContext *av_bitstream_filter_init(const char *name)
53 {
54     AVBitStreamFilterContext *ctx = NULL;
55     BSFCompatContext         *priv = NULL;
56     const AVBitStreamFilter *bsf;
57
58     bsf = av_bsf_get_by_name(name);
59     if (!bsf)
60         return NULL;
61
62     ctx = av_mallocz(sizeof(*ctx));
63     if (!ctx)
64         return NULL;
65
66     priv = av_mallocz(sizeof(*priv));
67     if (!priv)
68         goto fail;
69
70
71     ctx->filter    = bsf;
72     ctx->priv_data = priv;
73
74     return ctx;
75
76 fail:
77     if (priv)
78         av_bsf_free(&priv->ctx);
79     av_freep(&priv);
80     av_freep(&ctx);
81     return NULL;
82 }
83
84 void av_bitstream_filter_close(AVBitStreamFilterContext *bsfc)
85 {
86     BSFCompatContext *priv;
87
88     if (!bsfc)
89         return;
90
91     priv = bsfc->priv_data;
92
93     av_bsf_free(&priv->ctx);
94     av_freep(&bsfc->priv_data);
95     av_free(bsfc);
96 }
97
98 int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
99                                AVCodecContext *avctx, const char *args,
100                                uint8_t **poutbuf, int *poutbuf_size,
101                                const uint8_t *buf, int buf_size, int keyframe)
102 {
103     BSFCompatContext *priv = bsfc->priv_data;
104     AVPacket pkt = { 0 };
105     int ret;
106
107     if (!priv->ctx) {
108         ret = av_bsf_alloc(bsfc->filter, &priv->ctx);
109         if (ret < 0)
110             return ret;
111
112         ret = avcodec_parameters_from_context(priv->ctx->par_in, avctx);
113         if (ret < 0)
114             return ret;
115
116         priv->ctx->time_base_in = avctx->time_base;
117
118         if (bsfc->args && bsfc->filter->priv_class) {
119             const AVOption *opt = av_opt_next(priv->ctx->priv_data, NULL);
120             const char * shorthand[2] = {NULL};
121
122             if (opt)
123                 shorthand[0] = opt->name;
124
125             ret = av_opt_set_from_string(priv->ctx->priv_data, bsfc->args, shorthand, "=", ":");
126         }
127
128         ret = av_bsf_init(priv->ctx);
129         if (ret < 0)
130             return ret;
131     }
132
133     pkt.data = buf;
134     pkt.size = buf_size;
135
136     ret = av_bsf_send_packet(priv->ctx, &pkt);
137     if (ret < 0)
138         return ret;
139
140     *poutbuf      = NULL;
141     *poutbuf_size = 0;
142
143     ret = av_bsf_receive_packet(priv->ctx, &pkt);
144     if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
145         return 0;
146     else if (ret < 0)
147         return ret;
148
149     *poutbuf = av_malloc(pkt.size + AV_INPUT_BUFFER_PADDING_SIZE);
150     if (!*poutbuf) {
151         av_packet_unref(&pkt);
152         return AVERROR(ENOMEM);
153     }
154
155     *poutbuf_size = pkt.size;
156     memcpy(*poutbuf, pkt.data, pkt.size);
157
158     av_packet_unref(&pkt);
159
160     /* drain all the remaining packets we cannot return */
161     while (ret >= 0) {
162         ret = av_bsf_receive_packet(priv->ctx, &pkt);
163         av_packet_unref(&pkt);
164     }
165
166     if (!priv->extradata_updated) {
167         /* update extradata in avctx from the output codec parameters */
168         if (priv->ctx->par_out->extradata_size && (!args || !strstr(args, "private_spspps_buf"))) {
169             av_freep(&avctx->extradata);
170             avctx->extradata_size = 0;
171             avctx->extradata = av_mallocz(priv->ctx->par_out->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
172             if (!avctx->extradata)
173                 return AVERROR(ENOMEM);
174             memcpy(avctx->extradata, priv->ctx->par_out->extradata, priv->ctx->par_out->extradata_size);
175             avctx->extradata_size = priv->ctx->par_out->extradata_size;
176         }
177
178         priv->extradata_updated = 1;
179     }
180
181     return 1;
182 }
183 FF_ENABLE_DEPRECATION_WARNINGS
184 #endif