FFmpeg
Loading...
Searching...
No Matches
pcm_rechunk.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Marton Balint
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 "libavcodec/bsf.h"
23#include "libavutil/avassert.h"
24#include "libavutil/opt.h"
25
38
39static int init(AVBSFContext *ctx)
40{
41 PCMContext *s = ctx->priv_data;
42 AVRational sr = av_make_q(ctx->par_in->sample_rate, 1);
43 int64_t min_samples;
44
45 if (ctx->par_in->ch_layout.nb_channels <= 0 || ctx->par_in->sample_rate <= 0)
46 return AVERROR(EINVAL);
47
48 ctx->time_base_out = av_inv_q(sr);
49 s->sample_size = ctx->par_in->ch_layout.nb_channels *
50 av_get_bits_per_sample(ctx->par_in->codec_id) / 8;
51
52 if (s->frame_rate.num) {
53 min_samples = av_rescale_q_rnd(1, sr, s->frame_rate, AV_ROUND_DOWN);
54 } else {
55 min_samples = s->nb_out_samples;
56 }
57 if (min_samples <= 0 || min_samples > INT_MAX / s->sample_size - 1)
58 return AVERROR(EINVAL);
59
60 s->in_pkt = av_packet_alloc();
61 s->out_pkt = av_packet_alloc();
62 if (!s->in_pkt || !s->out_pkt)
63 return AVERROR(ENOMEM);
64
65 return 0;
66}
67
68static void uninit(AVBSFContext *ctx)
69{
70 PCMContext *s = ctx->priv_data;
71 av_packet_free(&s->in_pkt);
72 av_packet_free(&s->out_pkt);
73}
74
75static void flush(AVBSFContext *ctx)
76{
77 PCMContext *s = ctx->priv_data;
78 av_packet_unref(s->in_pkt);
79 av_packet_unref(s->out_pkt);
80 s->n = 0;
81}
82
83static int send_packet(PCMContext *s, int nb_samples, AVPacket *pkt)
84{
85 pkt->duration = nb_samples;
86 s->n++;
87 return 0;
88}
89
90static void drain_packet(AVPacket *pkt, int drain_data, int drain_samples)
91{
92 pkt->size -= drain_data;
93 pkt->data += drain_data;
94 if (pkt->dts != AV_NOPTS_VALUE)
95 pkt->dts += drain_samples;
96 if (pkt->pts != AV_NOPTS_VALUE)
97 pkt->pts += drain_samples;
98}
99
101{
102 PCMContext *s = ctx->priv_data;
103 if (s->frame_rate.num) {
104 AVRational sr = av_make_q(ctx->par_in->sample_rate, 1);
105 return av_rescale_q(s->n + 1, sr, s->frame_rate) - av_rescale_q(s->n, sr, s->frame_rate);
106 } else {
107 return s->nb_out_samples;
108 }
109}
110
111static void set_silence(AVCodecParameters *par, uint8_t *buf, size_t size)
112{
113 int c = 0;
114 switch (par->codec_id) {
115 case AV_CODEC_ID_PCM_ALAW: c = 0xd5; break;
117 case AV_CODEC_ID_PCM_VIDC: c = 0xff; break;
118 case AV_CODEC_ID_PCM_U8: c = 0x80; break;
119 }
120 memset(buf, c, size);
121}
122
124{
125 PCMContext *s = ctx->priv_data;
126 int nb_samples = get_next_nb_samples(ctx);
127 int data_size = nb_samples * s->sample_size;
128 int ret;
129
130 do {
131 if (s->in_pkt->size) {
132 if (s->out_pkt->size || s->in_pkt->size < data_size) {
133 int drain = FFMIN(s->in_pkt->size, data_size - s->out_pkt->size);
134 if (!s->out_pkt->size) {
135 ret = av_new_packet(s->out_pkt, data_size);
136 if (ret < 0)
137 return ret;
138 ret = av_packet_copy_props(s->out_pkt, s->in_pkt);
139 if (ret < 0) {
140 av_packet_unref(s->out_pkt);
141 return ret;
142 }
143 s->out_pkt->size = 0;
144 }
145 memcpy(s->out_pkt->data + s->out_pkt->size, s->in_pkt->data, drain);
146 s->out_pkt->size += drain;
147 drain_packet(s->in_pkt, drain, drain / s->sample_size);
148 if (!s->in_pkt->size)
149 av_packet_unref(s->in_pkt);
150 if (s->out_pkt->size == data_size) {
151 av_packet_move_ref(pkt, s->out_pkt);
152 return send_packet(s, nb_samples, pkt);
153 }
154 av_assert0(!s->in_pkt->size);
155 } else if (s->in_pkt->size > data_size) {
156 ret = av_packet_ref(pkt, s->in_pkt);
157 if (ret < 0)
158 return ret;
159 pkt->size = data_size;
160 drain_packet(s->in_pkt, data_size, nb_samples);
161 return send_packet(s, nb_samples, pkt);
162 } else {
163 av_assert0(s->in_pkt->size == data_size);
164 av_packet_move_ref(pkt, s->in_pkt);
165 return send_packet(s, nb_samples, pkt);
166 }
167 } else
168 av_packet_unref(s->in_pkt);
169
170 ret = ff_bsf_get_packet_ref(ctx, s->in_pkt);
171 if (ret == AVERROR_EOF && s->out_pkt->size) {
172 if (s->pad) {
173 set_silence(ctx->par_in, s->out_pkt->data + s->out_pkt->size, data_size - s->out_pkt->size);
174 s->out_pkt->size = data_size;
175 } else {
176 nb_samples = s->out_pkt->size / s->sample_size;
177 }
178 av_packet_move_ref(pkt, s->out_pkt);
179 return send_packet(s, nb_samples, pkt);
180 }
181 if (ret >= 0)
182 av_packet_rescale_ts(s->in_pkt, ctx->time_base_in, ctx->time_base_out);
183 } while (ret >= 0);
184
185 return ret;
186}
187
188#define OFFSET(x) offsetof(PCMContext, x)
189#define FLAGS (AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_BSF_PARAM)
190static const AVOption options[] = {
191 { "nb_out_samples", "set the number of per-packet output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
192 { "n", "set the number of per-packet output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
193 { "pad", "pad last packet with zeros", OFFSET(pad), AV_OPT_TYPE_BOOL, {.i64=1} , 0, 1, FLAGS },
194 { "p", "pad last packet with zeros", OFFSET(pad), AV_OPT_TYPE_BOOL, {.i64=1} , 0, 1, FLAGS },
195 { "frame_rate", "set number of packets per second", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS },
196 { "r", "set number of packets per second", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS },
197 { NULL },
198};
199
201 .class_name = "pcm_rechunk_bsf",
202 .item_name = av_default_item_name,
203 .option = options,
204 .version = LIBAVUTIL_VERSION_INT,
205};
206
231
233 .p.name = "pcm_rechunk",
234 .p.codec_ids = codec_ids,
235 .p.priv_class = &pcm_rechunk_class,
236 .priv_data_size = sizeof(PCMContext),
238 .init = init,
239 .flush = flush,
240 .close = uninit,
241};
static enum AVCodecID codec_ids[]
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
const FFBitStreamFilter ff_pcm_rechunk_bsf
int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
Called by bitstream filters to get packet for filtering.
Definition bsf.c:254
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVPacket * pkt
void(* flush)(AVBSFContext *ctx)
Definition dts2pts.c:610
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
@ AV_OPT_TYPE_RATIONAL
Underlying C type is AVRational.
Definition opt.h:279
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
int av_get_bits_per_sample(enum AVCodecID codec_id)
Return codec bits per sample.
Definition utils.c:556
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition codec_id.h:47
@ AV_CODEC_ID_PCM_F24LE
Definition codec_id.h:364
@ AV_CODEC_ID_PCM_F32LE
Definition codec_id.h:351
@ AV_CODEC_ID_PCM_S24BE
Definition codec_id.h:343
@ AV_CODEC_ID_PCM_S64BE
Definition codec_id.h:362
@ AV_CODEC_ID_PCM_U8
Definition codec_id.h:335
@ AV_CODEC_ID_PCM_S16LE
Definition codec_id.h:330
@ AV_CODEC_ID_PCM_F16LE
Definition codec_id.h:363
@ AV_CODEC_ID_PCM_F32BE
Definition codec_id.h:350
@ AV_CODEC_ID_NONE
Definition codec_id.h:48
@ AV_CODEC_ID_PCM_S16BE
Definition codec_id.h:331
@ AV_CODEC_ID_PCM_S24LE
Definition codec_id.h:342
@ AV_CODEC_ID_PCM_S24DAUD
Definition codec_id.h:346
@ AV_CODEC_ID_PCM_S32LE
Definition codec_id.h:338
@ AV_CODEC_ID_PCM_S8
Definition codec_id.h:334
@ AV_CODEC_ID_PCM_VIDC
Definition codec_id.h:365
@ AV_CODEC_ID_PCM_ALAW
Definition codec_id.h:337
@ AV_CODEC_ID_PCM_F64LE
Definition codec_id.h:353
@ AV_CODEC_ID_PCM_SGA
Definition codec_id.h:366
@ AV_CODEC_ID_PCM_S64LE
Definition codec_id.h:361
@ AV_CODEC_ID_PCM_F64BE
Definition codec_id.h:352
@ AV_CODEC_ID_PCM_S32BE
Definition codec_id.h:339
@ AV_CODEC_ID_PCM_MULAW
Definition codec_id.h:336
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition packet.c:74
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:434
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
Definition packet.c:491
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition packet.c:63
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition packet.c:442
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
Copy only "properties" fields from src to dst.
Definition packet.c:397
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition packet.c:98
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
Convert valid timing fields (timestamps / durations) in a packet from one timebase to another.
Definition packet.c:538
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition rational.h:159
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, enum AVRounding rnd)
Rescale a 64-bit integer by 2 rational numbers with specified rounding.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AV_ROUND_DOWN
Round toward -infinity.
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
static av_cold void uninit(AVBitStreamFilterContext *ctx)
#define FFMIN(a, b)
Definition macros.h:49
AVOptions.
static int rechunk_filter(AVBSFContext *ctx, AVPacket *pkt)
static const AVClass pcm_rechunk_class
static int send_packet(PCMContext *s, int nb_samples, AVPacket *pkt)
Definition pcm_rechunk.c:83
static void uninit(AVBSFContext *ctx)
Definition pcm_rechunk.c:68
static void drain_packet(AVPacket *pkt, int drain_data, int drain_samples)
Definition pcm_rechunk.c:90
static void set_silence(AVCodecParameters *par, uint8_t *buf, size_t size)
static int get_next_nb_samples(AVBSFContext *ctx)
#define OFFSET(x)
The bitstream filter state.
Definition bsf.h:68
Describe the class of an AVClass context structure.
Definition log.h:76
This struct describes the properties of an encoded stream.
Definition codec_par.h:49
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
Rational number (pair of numerator and denominator).
Definition rational.h:58
int sample_size
Definition pcm_rechunk.c:35
int64_t n
Definition pcm_rechunk.c:36
AVPacket * out_pkt
Definition pcm_rechunk.c:34
AVRational frame_rate
Definition pcm_rechunk.c:31
int nb_out_samples
Definition pcm_rechunk.c:29
AVPacket * in_pkt
Definition pcm_rechunk.c:33
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
Definition h263dsp.c:29
static AVFormatContext * ctx
Definition movenc.c:49
int size
static double c[64]