AVPKit
BufferSink.cpp
1 /*******************************************************************************
2  * Copyright (c) 2024, 2026, Olivier Ayache. All rights reserved.
3  *
4  * This file is part of AVPKit.
5  *
6  * AVPKit is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * AVPKit 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
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with AVPKit. If not, see <http://www.gnu.org/licenses/>.
18  *******************************************************************************/
19 
20 #include <com/avpkit/core/BufferSink.h>
21 #include <com/avpkit/core/AudioSamples.h>
22 #include <com/avpkit/ferry/Logger.h>
23 #include <stdbool.h>
24 
25 extern "C" {
26 #include "libavutil/channel_layout.h"
27 #include "VideoPicture.h"
28 #include "Rational.h"
29 }
30 
31 VS_LOG_SETUP(VS_CPP_PACKAGE);
32 
33 
34 
35 namespace com {
36  namespace avpkit {
37  namespace core {
38 
39  using namespace com::avpkit::ferry;
40 
42  return av_buffersink_get_channels(mSinkFilterContext);
43  }
44 
46  return av_buffersink_get_sample_rate(mSinkFilterContext);
47  }
48 
50  return av_buffersink_get_w(mSinkFilterContext);
51  }
52 
54  return av_buffersink_get_h(mSinkFilterContext);
55  }
56 
58  AVRational frameRate = av_buffersink_get_frame_rate(mSinkFilterContext);
59  return IRational::make(frameRate.num, frameRate.den);
60  }
61 
63  AVRational frameRate = av_buffersink_get_time_base(mSinkFilterContext);
64  return IRational::make(frameRate.num, frameRate.den);
65  }
66 
67  void BufferSink::setNumSamples(int frameSize) {
68  av_buffersink_set_frame_size(mSinkFilterContext, frameSize);
69  }
70 
71  void BufferSink::setReady() {
72  mTimeBase.reset(getTimeBase(), true);
73  MediaFilter::setReady();
74  }
75 
77  int retval = -1;
78  if (!ready) {
79  return -1;
80  }
81  if (samples) {
82  AudioSamples* outSamples = static_cast<AudioSamples*> (samples);
83  if (outSamples) {
84  outSamples->setComplete(false, 0, outSamples->getSampleRate(), outSamples->getChannels(), outSamples->getChannelLayout(),
86  AVFrame* frame = av_frame_alloc();
87  if (frame) {
88  retval = av_buffersink_get_frame(mSinkFilterContext, frame);
89  if (retval == AVERROR(EAGAIN)) {
90  //VS_LOG_WARN("No data available retry later");
91  } else if (retval >= 0) {
92  int buffer_size;
93  buffer_size = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, (AVSampleFormat) frame->format, 0);
94  outSamples->ensureCapacity(buffer_size);
95  memcpy(outSamples->getRawSamples(0), frame->extended_data[0], buffer_size);
96  IRational* timeBase = outSamples->getTimeBase();
97  outSamples->setComplete(true,
98  frame->nb_samples,
99  frame->sample_rate,
100  frame->channels,
101  (IAudioSamples::ChannelLayout)frame->channel_layout,
103  timeBase->rescale(frame->pts, mTimeBase.value()));
104  VS_REF_RELEASE(timeBase);
105  }
106  av_frame_free(&frame);
107  }
108  }
109  }
110  return retval;
111  }
112 
114  int retval = -1;
115  if (!ready) {
116  return -1;
117  }
118  if (picture) {
119  VideoPicture* outPicture = static_cast<VideoPicture*> (picture);
120 
121  if (picture) {
122  outPicture->setComplete(false, IPixelFormat::NONE, outPicture->getWidth(), outPicture->getHeight(), 0);
123  AVFrame* frame = av_frame_alloc();
124  if (frame) {
125  retval = av_buffersink_get_frame(mSinkFilterContext, frame);
126  if (retval == AVERROR(EAGAIN)) {
127  //VS_LOG_WARN("No data available retry later");
128  } else if (retval >= 0) {
129  outPicture->copyAVFrame(frame, (IPixelFormat::Type)frame->format, frame->width, frame->height);
130  IRational* timeBase = outPicture->getTimeBase();
131  outPicture->setComplete(true,
132  (IPixelFormat::Type)frame->format,
133  frame->width,
134  frame->height,
135  timeBase->rescale(frame->pts, mTimeBase.value()));
136  VS_REF_RELEASE(timeBase);
137  }
138  av_frame_free(&frame);
139  }
140  }
141  }
142  return retval;
143  }
144 
145  BufferSink::BufferSink() {
146  mSinkFilterContext = NULL;
147  mSinkFilter = NULL;
148  mTimeBase = IRational::make(1, 1000000);
149  }
150 
151  BufferSink::~BufferSink() {
152  //mSinkFilterContext freed by FilterChain
153  mSinkFilterContext = NULL;
154  mSinkFilter = NULL;
155  mTimeBase = NULL;
156  }
157 
158  BufferSink* BufferSink::make(AVFilterGraph* graph, IAudioSamples::ChannelLayout channel_layout) {
159 
160  BufferSink* retval = NULL;
161 
162  retval = BufferSink::make();
163 
164  if (retval) {
165  retval->mFilter = avfilter_get_by_name("aformat");
166  retval->mSinkFilter = avfilter_get_by_name("abuffersink");
167  retval->mFilterContext = avfilter_graph_alloc_filter(graph, retval->mFilter, "aformat");
168  if (!retval->mFilterContext) {
169  VS_REF_RELEASE(retval);
170  } else {
171  av_opt_set(retval->mFilterContext, "sample_fmts", "s16", AV_OPT_SEARCH_CHILDREN);
172  if (channel_layout != IAudioSamples::ChannelLayout::CH_NONE) {
173  char ch_layout[64];
174  av_get_channel_layout_string(ch_layout,
175  sizeof (ch_layout),
176  0,
177  (uint64_t) channel_layout);
178  av_opt_set(retval->mFilterContext, "channel_layouts", ch_layout, AV_OPT_SEARCH_CHILDREN);
179  }
180  if (avfilter_init_str(retval->mFilterContext, NULL) < 0) {
181  VS_REF_RELEASE(retval);
182  } else {
183  retval->mSinkFilterContext = avfilter_graph_alloc_filter(graph, retval->mSinkFilter, "abuffersink");
184  if (!retval->mSinkFilterContext) {
185  VS_REF_RELEASE(retval);
186  } else {
187  av_opt_set_int(retval->mSinkFilterContext, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN);
188  if (avfilter_init_str(retval->mSinkFilterContext, NULL) < 0) {
189  VS_REF_RELEASE(retval);
190  } else {
191  retval->mFilterGraph = graph;
192  if (avfilter_link(retval->mFilterContext, 0, retval->mSinkFilterContext, 0) < 0) {
193  VS_REF_RELEASE(retval);
194  }
195  }
196 
197  }
198  }
199 
200  }
201 
202  }
203 
204  return retval;
205  }
206 
207  BufferSink* BufferSink::make(AVFilterGraph* graph, IPixelFormat::Type pixel_type) {
208  BufferSink* retval = NULL;
209 
210  retval = BufferSink::make();
211 
212  if (retval) {
213  retval->mFilter = avfilter_get_by_name("format");
214  retval->mSinkFilter = avfilter_get_by_name("buffersink");
215  retval->mFilterContext = avfilter_graph_alloc_filter(graph, retval->mFilter, "format");
216  if (!retval->mFilterContext) {
217  VS_REF_RELEASE(retval);
218  } else {
219  av_opt_set(retval->mFilterContext, "pix_fmts", pixel_type == IPixelFormat::NONE ? "yuv420p" : av_get_pix_fmt_name((AVPixelFormat) pixel_type), AV_OPT_SEARCH_CHILDREN);
220  if (avfilter_init_str(retval->mFilterContext, NULL) < 0) {
221  VS_REF_RELEASE(retval);
222  } else {
223  retval->mSinkFilterContext = avfilter_graph_alloc_filter(graph, retval->mSinkFilter, "buffersink");
224  if (!retval->mSinkFilterContext) {
225  VS_REF_RELEASE(retval);
226  } else {
227  if (avfilter_init_str(retval->mSinkFilterContext, NULL) < 0) {
228  VS_REF_RELEASE(retval);
229  } else {
230  retval->mFilterGraph = graph;
231  if (avfilter_link(retval->mFilterContext, 0, retval->mSinkFilterContext, 0) < 0) {
232  VS_REF_RELEASE(retval);
233  }
234  }
235 
236  }
237  }
238 
239  }
240 
241  }
242 
243  return retval;
244  }
245 
246  }
247  }
248 }
249 
virtual int32_t getSampleRate()
Find the sample rate of the samples in this audio buffer.
virtual int32_t getChannels()
Return the number of channels of the samples in this buffer.
virtual IRational * getTimeBase()
Get the time base that time stamps of this object are represented in.
Definition: AudioSamples.h:39
virtual int32_t ensureCapacity(int32_t capacityInBytes)
Called by decoder before decoding to ensure sufficient space.
virtual void setComplete(bool complete, int32_t numSamples, int32_t sampleRate, int32_t channels, Format sampleFmt, int64_t pts)
Call this if you modify the samples and are now done.
virtual int getChannels()
Returns the channel number of output filtered samples.
Definition: BufferSink.cpp:41
virtual IRational * getTimeBase()
Returns the frame rate output filtered picture.
Definition: BufferSink.cpp:62
virtual int getWidth()
Returns the width of output filtered picture.
Definition: BufferSink.cpp:49
virtual void setNumSamples(int frameSize)
Sets the number of samples for each output filtered samples.
Definition: BufferSink.cpp:67
virtual IRational * getFrameRate()
Returns the frame rate output filtered picture.
Definition: BufferSink.cpp:57
virtual int getHeight()
Returns the height of output filtered picture.
Definition: BufferSink.cpp:53
virtual int fillVideoPicture(IVideoPicture *picture)
Fills this video picture with filtered data.
Definition: BufferSink.cpp:113
virtual int getSampleRate()
Returns the sample rate of output filtered samples.
Definition: BufferSink.cpp:45
virtual int fillAudioSamples(IAudioSamples *samples)
Fills this audio samples with filtered data.
Definition: BufferSink.cpp:76
A set of raw (decoded) samples, plus a timestamp for when to play those samples relative to other ite...
Definition: IAudioSamples.h:38
This class wraps represents a Rational number for the AVPKit.
Definition: IRational.h:43
static IRational * make()
Get a new rational that will be set to 0/0.
Definition: IRational.cpp:79
virtual int64_t rescale(int64_t origValue, IRational *origBase)=0
Takes a value scaled in increments of origBase and gives the equivalent value scaled in terms of this...
Represents one raw (undecoded) picture in a video stream, plus a timestamp for when to display that v...
Definition: IVideoPicture.h:40
virtual void setComplete(bool aIsComplete, IPixelFormat::Type format, int width, int height, int64_t pts)
After modifying the raw data in this buffer, call this function to let the object know it is now comp...
void copyAVFrame(AVFrame *frame, IPixelFormat::Type pixel, int32_t width, int32_t height)
Called by the StreamCoder once it's done decoding.
virtual int getWidth()
What is the width of the picture.
Definition: VideoPicture.h:48
virtual int getHeight()
What is the height of the picture.
Definition: VideoPicture.h:49
virtual IRational * getTimeBase()
Get the time base that time stamps of this object are represented in.
Definition: VideoPicture.h:41
This library contains routines used by AVPKit libraries for "ferry"ing Java objects to and from nativ...
WARNING: Do not use logging in this class, and do not set any static file variables to values other t...