FFmpeg  4.4.5
pcm_rechunk_bsf.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 "avcodec.h"
22 #include "bsf_internal.h"
23 #include "libavutil/avassert.h"
24 #include "libavutil/opt.h"
25 
26 typedef struct PCMContext {
27  const AVClass *class;
28 
30  int pad;
32 
37 } PCMContext;
38 
39 static int init(AVBSFContext *ctx)
40 {
42  AVRational sr = av_make_q(ctx->par_in->sample_rate, 1);
43  int64_t min_samples;
44 
45  if (ctx->par_in->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->channels * av_get_bits_per_sample(ctx->par_in->codec_id) / 8;
50 
51  if (s->frame_rate.num) {
52  min_samples = av_rescale_q_rnd(1, sr, s->frame_rate, AV_ROUND_DOWN);
53  } else {
54  min_samples = s->nb_out_samples;
55  }
56  if (min_samples <= 0 || min_samples > INT_MAX / s->sample_size - 1)
57  return AVERROR(EINVAL);
58 
59  s->in_pkt = av_packet_alloc();
60  s->out_pkt = av_packet_alloc();
61  if (!s->in_pkt || !s->out_pkt)
62  return AVERROR(ENOMEM);
63 
64  return 0;
65 }
66 
67 static void uninit(AVBSFContext *ctx)
68 {
70  av_packet_free(&s->in_pkt);
71  av_packet_free(&s->out_pkt);
72 }
73 
74 static void flush(AVBSFContext *ctx)
75 {
77  av_packet_unref(s->in_pkt);
78  av_packet_unref(s->out_pkt);
79  s->n = 0;
80 }
81 
82 static int send_packet(PCMContext *s, int nb_samples, AVPacket *pkt)
83 {
84  pkt->duration = nb_samples;
85  s->n++;
86  return 0;
87 }
88 
89 static void drain_packet(AVPacket *pkt, int drain_data, int drain_samples)
90 {
91  pkt->size -= drain_data;
92  pkt->data += drain_data;
93  if (pkt->dts != AV_NOPTS_VALUE)
94  pkt->dts += drain_samples;
95  if (pkt->pts != AV_NOPTS_VALUE)
96  pkt->pts += drain_samples;
97 }
98 
100 {
102  if (s->frame_rate.num) {
103  AVRational sr = av_make_q(ctx->par_in->sample_rate, 1);
104  return av_rescale_q(s->n + 1, sr, s->frame_rate) - av_rescale_q(s->n, sr, s->frame_rate);
105  } else {
106  return s->nb_out_samples;
107  }
108 }
109 
111 {
113  int nb_samples = get_next_nb_samples(ctx);
114  int data_size = nb_samples * s->sample_size;
115  int ret;
116 
117  do {
118  if (s->in_pkt->size) {
119  if (s->out_pkt->size || s->in_pkt->size < data_size) {
120  int drain = FFMIN(s->in_pkt->size, data_size - s->out_pkt->size);
121  if (!s->out_pkt->size) {
122  ret = av_new_packet(s->out_pkt, data_size);
123  if (ret < 0)
124  return ret;
125  ret = av_packet_copy_props(s->out_pkt, s->in_pkt);
126  if (ret < 0) {
127  av_packet_unref(s->out_pkt);
128  return ret;
129  }
130  s->out_pkt->size = 0;
131  }
132  memcpy(s->out_pkt->data + s->out_pkt->size, s->in_pkt->data, drain);
133  s->out_pkt->size += drain;
134  drain_packet(s->in_pkt, drain, drain / s->sample_size);
135  if (!s->in_pkt->size)
136  av_packet_unref(s->in_pkt);
137  if (s->out_pkt->size == data_size) {
138  av_packet_move_ref(pkt, s->out_pkt);
139  return send_packet(s, nb_samples, pkt);
140  }
141  } else if (s->in_pkt->size > data_size) {
142  ret = av_packet_ref(pkt, s->in_pkt);
143  if (ret < 0)
144  return ret;
145  pkt->size = data_size;
146  drain_packet(s->in_pkt, data_size, nb_samples);
147  return send_packet(s, nb_samples, pkt);
148  } else {
149  av_assert0(s->in_pkt->size == data_size);
150  av_packet_move_ref(pkt, s->in_pkt);
151  return send_packet(s, nb_samples, pkt);
152  }
153  }
154 
155  ret = ff_bsf_get_packet_ref(ctx, s->in_pkt);
156  if (ret == AVERROR_EOF && s->out_pkt->size) {
157  if (s->pad) {
158  memset(s->out_pkt->data + s->out_pkt->size, 0, data_size - s->out_pkt->size);
159  s->out_pkt->size = data_size;
160  } else {
161  nb_samples = s->out_pkt->size / s->sample_size;
162  }
163  av_packet_move_ref(pkt, s->out_pkt);
164  return send_packet(s, nb_samples, pkt);
165  }
166  if (ret >= 0)
167  av_packet_rescale_ts(s->in_pkt, ctx->time_base_in, ctx->time_base_out);
168  } while (ret >= 0);
169 
170  return ret;
171 }
172 
173 #define OFFSET(x) offsetof(PCMContext, x)
174 #define FLAGS (AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_BSF_PARAM)
175 static const AVOption options[] = {
176  { "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 },
177  { "n", "set the number of per-packet output samples", OFFSET(nb_out_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS },
178  { "pad", "pad last packet with zeros", OFFSET(pad), AV_OPT_TYPE_BOOL, {.i64=1} , 0, 1, FLAGS },
179  { "p", "pad last packet with zeros", OFFSET(pad), AV_OPT_TYPE_BOOL, {.i64=1} , 0, 1, FLAGS },
180  { "frame_rate", "set number of packets per second", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS },
181  { "r", "set number of packets per second", OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS },
182  { NULL },
183 };
184 
185 static const AVClass pcm_rechunk_class = {
186  .class_name = "pcm_rechunk_bsf",
187  .item_name = av_default_item_name,
188  .option = options,
189  .version = LIBAVUTIL_VERSION_INT,
190 };
191 
192 static const enum AVCodecID codec_ids[] = {
209 };
210 
212  .name = "pcm_rechunk",
213  .priv_data_size = sizeof(PCMContext),
214  .priv_class = &pcm_rechunk_class,
216  .init = init,
217  .flush = flush,
218  .close = uninit,
219  .codec_ids = codec_ids,
220 };
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:37
Libavcodec external API header.
int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
Called by bitstream filters to get packet for filtering.
Definition: bsf.c:253
#define s(width, name)
Definition: cbs_vp9.c:257
static av_always_inline void filter(int16_t *output, ptrdiff_t out_stride, const int16_t *low, ptrdiff_t low_stride, const int16_t *high, ptrdiff_t high_stride, int len, int clip)
Definition: cfhddsp.c:27
#define FFMIN(a, b)
Definition: common.h:105
#define NULL
Definition: coverity.c:32
long long int64_t
Definition: coverity.c:34
@ AV_OPT_TYPE_RATIONAL
Definition: opt.h:230
@ AV_OPT_TYPE_INT
Definition: opt.h:225
@ AV_OPT_TYPE_BOOL
Definition: opt.h:242
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:46
@ AV_CODEC_ID_PCM_F24LE
Definition: codec_id.h:348
@ AV_CODEC_ID_PCM_F32LE
Definition: codec_id.h:334
@ AV_CODEC_ID_PCM_S24BE
Definition: codec_id.h:326
@ AV_CODEC_ID_PCM_S64BE
Definition: codec_id.h:346
@ AV_CODEC_ID_PCM_S16LE
Definition: codec_id.h:313
@ AV_CODEC_ID_PCM_F16LE
Definition: codec_id.h:347
@ AV_CODEC_ID_PCM_F32BE
Definition: codec_id.h:333
@ AV_CODEC_ID_NONE
Definition: codec_id.h:47
@ AV_CODEC_ID_PCM_S16BE
Definition: codec_id.h:314
@ AV_CODEC_ID_PCM_S24LE
Definition: codec_id.h:325
@ AV_CODEC_ID_PCM_S32LE
Definition: codec_id.h:321
@ AV_CODEC_ID_PCM_S8
Definition: codec_id.h:317
@ AV_CODEC_ID_PCM_F64LE
Definition: codec_id.h:336
@ AV_CODEC_ID_PCM_S64LE
Definition: codec_id.h:345
@ AV_CODEC_ID_PCM_F64BE
Definition: codec_id.h:335
@ AV_CODEC_ID_PCM_S32BE
Definition: codec_id.h:322
int av_get_bits_per_sample(enum AVCodecID codec_id)
Return codec bits per sample.
Definition: utils.c:636
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: avpacket.c:75
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:634
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
Definition: avpacket.c:690
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: avpacket.c:64
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition: avpacket.c:641
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
Copy only "properties" fields from src to dst.
Definition: avpacket.c:600
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:99
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: avpacket.c:737
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define AVERROR(e)
Definition: error.h:43
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
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
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:82
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.
Definition: mathematics.c:134
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVOptions.
static int init(AVBSFContext *ctx)
static int rechunk_filter(AVBSFContext *ctx, AVPacket *pkt)
static enum AVCodecID codec_ids[]
static const AVClass pcm_rechunk_class
static void flush(AVBSFContext *ctx)
static const AVOption options[]
static int send_packet(PCMContext *s, int nb_samples, AVPacket *pkt)
#define FLAGS
static void uninit(AVBSFContext *ctx)
static void drain_packet(AVPacket *pkt, int drain_data, int drain_samples)
static int get_next_nb_samples(AVBSFContext *ctx)
#define OFFSET(x)
const AVBitStreamFilter ff_pcm_rechunk_bsf
The bitstream filter state.
Definition: bsf.h:49
const char * name
Definition: bsf.h:99
Describe the class of an AVClass context structure.
Definition: log.h:67
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
void * priv_data
Format private data.
Definition: avformat.h:1260
AVOption.
Definition: opt.h:248
This structure stores compressed data.
Definition: packet.h:346
int size
Definition: packet.h:370
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:387
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:362
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition: packet.h:368
uint8_t * data
Definition: packet.h:369
Rational number (pair of numerator and denominator).
Definition: rational.h:58
AVPacket * out_pkt
AVRational frame_rate
AVPacket * in_pkt
AVPacket * pkt
Definition: movenc.c:59
AVFormatContext * ctx
Definition: movenc.c:48