AVPKit
BufferSource.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/BufferSource.h>
21 #include <com/avpkit/core/AudioSamples.h>
22 #include <com/avpkit/core/VideoPicture.h>
23 #include <com/avpkit/ferry/Logger.h>
24 
25 VS_LOG_SETUP(VS_CPP_PACKAGE);
26 
27 
28 extern "C" {
29 #include "libavcodec/avcodec.h"
30 #include "libavfilter/avfilter.h"
31 #include "libavutil/opt.h"
32 }
33 
34 namespace com {
35  namespace avpkit {
36  namespace core {
37 
39  int retval = -1;
40  if (!mFilterContext || !ready) {
41  VS_LOG_ERROR("Try to add samples to an unitialized abuffer");
42  return retval;
43  }
44  if (samples) {
45  AudioSamples* inSamples = static_cast<AudioSamples*> (samples);
46  AVFrame* frame = av_frame_alloc();
47  if (frame) {
48  frame->nb_samples = inSamples->getNumSamples();
49  frame->sample_rate = inSamples->getSampleRate();
50  frame->format = inSamples->getFormat();
51  frame->channels = inSamples->getChannels();
52  frame->channel_layout = (uint64_t) inSamples->getChannelLayout();
53  IRational* timeBase = inSamples->getTimeBase();
54  frame->pts = mTimeBase->rescale(inSamples->getPts(), timeBase);
55  VS_REF_RELEASE(timeBase);
56  int data_size = av_samples_get_buffer_size(&frame->linesize[0],
57  frame->channels,
58  frame->nb_samples,
59  (AVSampleFormat) frame->format,
60  0);
61  if (data_size >= 0) {
62  retval = avcodec_fill_audio_frame(frame,
63  frame->channels,
64  (AVSampleFormat) frame->format,
65  (const uint8_t*) inSamples->getRawSamples(0),
66  data_size,
67  0);
68  retval = av_buffersrc_write_frame(mFilterContext, frame);
69  } else {
70  av_frame_free(&frame);
71  }
72  if (retval < 0) {
73  av_frame_free(&frame);
74  }
75  av_frame_free(&frame);
76  }
77  } else {
78  retval = av_buffersrc_add_frame_flags(mFilterContext, NULL, AV_BUFFERSRC_FLAG_PUSH);
79  }
80 
81 
82  return retval;
83  }
84 
86  int retval = -1;
87  if (!mFilterContext || !ready) {
88  VS_LOG_ERROR("Try to add picture to an unitialized buffer");
89  return retval;
90  }
91  if (picture) {
92  AVFrame* frame = av_frame_alloc();
93  if (frame) {
94  VideoPicture* inPicture = static_cast<VideoPicture*> (picture);
95  IRational* timeBase = inPicture->getTimeBase();
96  int64_t pts = mTimeBase->rescale(inPicture->getPts(), timeBase);
97  VS_REF_RELEASE(timeBase);
98  av_frame_ref(frame, inPicture->getAVFrame());
99  frame->pts = pts;
100  retval = av_buffersrc_add_frame(mFilterContext, frame);
101  av_frame_free(&frame);
102  }
103  } else {
104  retval = av_buffersrc_add_frame_flags(mFilterContext, NULL, AV_BUFFERSRC_FLAG_PUSH);
105  }
106 
107  return retval;
108  }
109 
110  BufferSource::BufferSource() {
111  mTimeBase = IRational::make(1, 1000000);
112  mParams = av_buffersrc_parameters_alloc();
113  }
114 
115  BufferSource::~BufferSource() {
116  mTimeBase = NULL;
117  if (mParams->hw_frames_ctx) {
118  av_buffer_unref(&mParams->hw_frames_ctx);
119  }
120  av_free(mParams);
121  }
122 
123  BufferSource* BufferSource::make(AVFilterGraph* graph, IAudioSamples::Format format,
124  int channels,
125  int sample_rate,
126  IRational* time_base,
127  IAudioSamples::ChannelLayout channel_layout) {
128 
129  BufferSource* retval = NULL;
130 
131 
132  if (sample_rate > 0 && time_base) {
133  retval = BufferSource::make();
134 
135  if (retval) {
136  retval->mFilter = avfilter_get_by_name("abuffer");
137  retval->mFilterContext = avfilter_graph_alloc_filter(graph, retval->mFilter, "abuffer");
138  if (!retval->mFilterContext) {
139  VS_REF_RELEASE(retval);
140  } else {
141  char ch_layout[64];
142  av_get_channel_layout_string(ch_layout,
143  sizeof (ch_layout),
144  0,
145  channel_layout == IAudioSamples::ChannelLayout::CH_NONE ? av_get_default_channel_layout(channels) : (uint64_t) channel_layout);
146  av_opt_set_q(retval->mFilterContext, "time_base", (AVRational) {
147  time_base->getNumerator(), time_base->getDenominator()
148  }, AV_OPT_SEARCH_CHILDREN);
149  av_opt_set_int(retval->mFilterContext, "sample_rate", sample_rate, AV_OPT_SEARCH_CHILDREN);
150  av_opt_set(retval->mFilterContext, "sample_fmt", av_get_sample_fmt_name((AVSampleFormat) format), AV_OPT_SEARCH_CHILDREN);
151  av_opt_set(retval->mFilterContext, "channel_layout", ch_layout, AV_OPT_SEARCH_CHILDREN);
152  av_opt_set_int(retval->mFilterContext, "channels", channels, AV_OPT_SEARCH_CHILDREN);
153  if (avfilter_init_str(retval->mFilterContext, NULL) < 0) {
154  VS_REF_RELEASE(retval);
155  }
156  retval->mTimeBase.reset(time_base, true);
157  retval->mFilterGraph = graph;
158  }
159  }
160  }
161 
162  return retval;
163  }
164 
165  BufferSource* BufferSource::make(AVFilterGraph* graph, IPixelFormat::Type format,
166  int width,
167  int height,
168  IRational* frame_rate,
169  IRational* time_base) {
170 
171  BufferSource* retval = NULL;
172 
173 
174  if (width > 0 && height > 0 && time_base && frame_rate) {
175  retval = BufferSource::make();
176 
177  if (retval) {
178  retval->mFilter = avfilter_get_by_name("buffer");
179  retval->mFilterContext = avfilter_graph_alloc_filter(graph, retval->mFilter, "buffer");
180  if (!retval->mFilterContext) {
181  VS_REF_RELEASE(retval);
182  } else {
183  av_opt_set_q(retval->mFilterContext, "frame_rate", (AVRational) {
184  frame_rate->getNumerator(), frame_rate->getDenominator()
185  }, AV_OPT_SEARCH_CHILDREN);
186  av_opt_set_q(retval->mFilterContext, "time_base", (AVRational) {
187  time_base->getNumerator(), time_base->getDenominator()
188  }, AV_OPT_SEARCH_CHILDREN);
189  av_opt_set_q(retval->mFilterContext, "pixel_aspect", (AVRational) {
190  1, 1
191  }, AV_OPT_SEARCH_CHILDREN);
192  av_opt_set_int(retval->mFilterContext, "width", width, AV_OPT_SEARCH_CHILDREN);
193  av_opt_set_int(retval->mFilterContext, "height", height, AV_OPT_SEARCH_CHILDREN);
194  av_opt_set(retval->mFilterContext, "pix_fmt", av_get_pix_fmt_name((AVPixelFormat) format), AV_OPT_SEARCH_CHILDREN);
195  if (avfilter_init_str(retval->mFilterContext, NULL) < 0) {
196  VS_REF_RELEASE(retval);
197  }
198  retval->mTimeBase.reset(time_base, true);
199  retval->mFilterGraph = graph;
200  }
201  }
202  }
203 
204  return retval;
205  }
206 
207  BufferSource* BufferSource::make(AVFilterGraph* graph, IVideoPicture* picture, IRational* frame_rate) {
208  VideoPicture* inPicture = static_cast<VideoPicture*> (picture);
209  AVFrame* frame = inPicture->getAVFrame();
210  IRational* timeBase = picture->getTimeBase();
211  BufferSource* retval = make(graph, picture->getPixelType(), frame->width, frame->height, frame_rate, timeBase);
212  VS_REF_RELEASE(timeBase);
213  if (av_pix_fmt_desc_get((AVPixelFormat) picture->getPixelType())->flags & AV_PIX_FMT_FLAG_HWACCEL) {
214  AVBufferRef* hwCtx = inPicture->getAVFrame()->hw_frames_ctx;
215  if (hwCtx) {
216  retval->mParams->hw_frames_ctx = inPicture->getAVFrame()->hw_frames_ctx;
217  av_buffersrc_parameters_set(retval->mFilterContext, retval->mParams);
218  } else {
219  VS_LOG_WARN("hw_frames_ctx is NULL for hardware accelerated pixel format ");
220  }
221  // AVBufferRef* device_ctx = NULL;
222  // switch (format) {
223  // case AV_PIX_FMT_CUDA:
224  // if (av_hwdevice_ctx_create(&device_ctx, AV_HWDEVICE_TYPE_CUDA, NULL, NULL, 0) < 0) {
225  // VS_LOG_WARN("Unable to create device for type CUDA");
226  // }
227  // retval->mParams->hw_frames_ctx = av_hwframe_ctx_alloc(device_ctx);
228  // if (retval->mParams->hw_frames_ctx) {
229  // AVHWFramesContext* frame_context = (AVHWFramesContext*) retval->mParams->hw_frames_ctx->data;
230  // frame_context->height = height;
231  // frame_context->width = width;
232  // frame_context->format = AV_PIX_FMT_CUDA;
233  // frame_context->sw_format = AV_PIX_FMT_YUV420P;
234  // }
235  // av_hwframe_ctx_init(retval->mParams->hw_frames_ctx);
236  // av_buffersrc_parameters_set(retval->mFilterContext, retval->mParams);
237  // break;
238  // default:
239  // VS_LOG_WARN("For now only CUDA hardware is supported for BufferSource");
240  // }
241  }
242  return retval;
243 
244  }
245  }
246  }
247 }
248 
virtual int32_t getSampleRate()
Find the sample rate of the samples in this audio buffer.
virtual Format getFormat()
Find the Format of the samples in this 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 int64_t getPts()
What is the Presentation Time Stamp of this set of audio samples.
virtual int32_t getNumSamples()
Get the number of samples in this video.
virtual int addVideoPicture(IVideoPicture *picture)
Adds picture to this filter.
virtual int addAudioSamples(IAudioSamples *samples)
Adds audio samples to this filter.
A set of raw (decoded) samples, plus a timestamp for when to play those samples relative to other ite...
Definition: IAudioSamples.h:38
Format
The format we use to represent audio.
Definition: IAudioSamples.h:46
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
Represents one raw (undecoded) picture in a video stream, plus a timestamp for when to display that v...
Definition: IVideoPicture.h:40
virtual int64_t getPts()
What is the Presentation Time Stamp (in Microseconds) of this picture.
virtual IRational * getTimeBase()
Get the time base that time stamps of this object are represented in.
Definition: VideoPicture.h:41
VS_API_AVPKIT AVFrame * getAVFrame()
Call to get the raw underlying AVFrame we manage; don't pass this to ffmpeg directly as ffmpeg often ...
WARNING: Do not use logging in this class, and do not set any static file variables to values other t...