@0biwank/screen-capture 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -6
- package/prebuilds/SHA256SUMS +2 -2
- package/prebuilds/darwin-arm64/native_capture.node +0 -0
- package/prebuilds/darwin-x64/native_capture.node +0 -0
- package/binding.gyp +0 -58
- package/include/CameraCapturer.h +0 -54
- package/include/DesktopCapturer.h +0 -83
- package/include/HLSMuxer/AudioEncoder.h +0 -75
- package/include/HLSMuxer/FileHLSMuxer.h +0 -63
- package/include/HLSMuxer/HLSMuxer.h +0 -13
- package/include/HLSMuxer/VideoEncoder.h +0 -90
- package/include/MediaPipeline.h +0 -39
- package/include/SourceHelper.h +0 -41
- package/include/SourceHelperWrapper.h +0 -29
- package/include/Types.h +0 -58
- package/include/UploadManager.h +0 -9
- package/include/httplib.h +0 -12065
- package/scripts/build-ffmpeg-vendor.mjs +0 -178
- package/scripts/build.mjs +0 -53
- package/scripts/stage-prebuild.mjs +0 -28
- package/scripts/verify-package.mjs +0 -39
- package/scripts/verify-packlist.mjs +0 -40
- package/scripts/verify-runtime.cjs +0 -28
- package/src/CameraCapturer.mm +0 -154
- package/src/DesktopCapturer.mm +0 -995
- package/src/HLSMuxer/AudioEncoder.cpp +0 -484
- package/src/HLSMuxer/FileHLSMuxer.cpp +0 -345
- package/src/HLSMuxer/HLSMuxer.cpp +0 -0
- package/src/HLSMuxer/VideoEncoder.cpp +0 -462
- package/src/MediaPipeline.cpp +0 -375
- package/src/MediaProcessor.cpp +0 -0
- package/src/SourceHelper.mm +0 -184
- package/src/SourceHelperWrapper.mm +0 -63
- package/src/UploadManager.h +0 -7
- package/src/addon.cpp +0 -347
- package/vendor/ffmpeg/README.md +0 -40
|
@@ -1,484 +0,0 @@
|
|
|
1
|
-
#include "HLSMuxer/AudioEncoder.h"
|
|
2
|
-
#include <iostream>
|
|
3
|
-
#include <sstream>
|
|
4
|
-
#include <iomanip>
|
|
5
|
-
#include <algorithm>
|
|
6
|
-
|
|
7
|
-
extern "C"
|
|
8
|
-
{
|
|
9
|
-
#include <libavcodec/avcodec.h>
|
|
10
|
-
#include <libavformat/avformat.h>
|
|
11
|
-
#include <libswresample/swresample.h>
|
|
12
|
-
#include <libavutil/opt.h>
|
|
13
|
-
#include <libavutil/channel_layout.h>
|
|
14
|
-
#include <libavutil/audio_fifo.h>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
AudioEncoder::AudioEncoder()
|
|
18
|
-
{
|
|
19
|
-
m_codecContext = nullptr;
|
|
20
|
-
m_codec = nullptr;
|
|
21
|
-
m_frame = nullptr;
|
|
22
|
-
m_swrContext = nullptr;
|
|
23
|
-
m_formatContext = nullptr;
|
|
24
|
-
m_stream = nullptr;
|
|
25
|
-
m_audioFifo = nullptr;
|
|
26
|
-
|
|
27
|
-
m_sampleCount = 0;
|
|
28
|
-
m_pts = 0;
|
|
29
|
-
m_nextInputPts = 0;
|
|
30
|
-
currentChunkIndex = 0;
|
|
31
|
-
m_initialized = false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
AudioEncoder::~AudioEncoder()
|
|
35
|
-
{
|
|
36
|
-
cleanup();
|
|
37
|
-
while (!m_packetQueue.empty())
|
|
38
|
-
{
|
|
39
|
-
AVPacket *pkt = m_packetQueue.front();
|
|
40
|
-
m_packetQueue.pop();
|
|
41
|
-
av_packet_free(&pkt);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
bool AudioEncoder::initialize(int sampleRate, int channels, int bitrate, OutputMode mode)
|
|
46
|
-
{
|
|
47
|
-
m_codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
|
|
48
|
-
if (!m_codec)
|
|
49
|
-
{
|
|
50
|
-
std::cerr << "AAC encoder not found!" << std::endl;
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
m_codecContext = avcodec_alloc_context3(m_codec);
|
|
54
|
-
if (!m_codecContext)
|
|
55
|
-
{
|
|
56
|
-
std::cerr << "Could not allocate codec context" << std::endl;
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
m_codecContext->bit_rate = bitrate;
|
|
60
|
-
m_codecContext->sample_fmt = AV_SAMPLE_FMT_FLTP;
|
|
61
|
-
m_codecContext->sample_rate = sampleRate;
|
|
62
|
-
av_channel_layout_default(&m_codecContext->ch_layout, channels);
|
|
63
|
-
|
|
64
|
-
m_sampleRate = sampleRate;
|
|
65
|
-
m_channels = channels;
|
|
66
|
-
m_bitrate = bitrate;
|
|
67
|
-
this->mode = mode;
|
|
68
|
-
|
|
69
|
-
int ret = avcodec_open2(m_codecContext, m_codec, nullptr);
|
|
70
|
-
if (ret < 0)
|
|
71
|
-
{
|
|
72
|
-
std::cerr << "Could not open codec" << std::endl;
|
|
73
|
-
cleanup();
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
// Set a sensible time base for audio frames (pts in samples)
|
|
77
|
-
m_codecContext->time_base = AVRational{1, sampleRate};
|
|
78
|
-
m_swrContext = swr_alloc();
|
|
79
|
-
if (!m_swrContext)
|
|
80
|
-
{
|
|
81
|
-
std::cerr << "Could not allocate SWR context" << std::endl;
|
|
82
|
-
cleanup();
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Set input and output parameters
|
|
87
|
-
av_opt_set_chlayout(m_swrContext, "in_chlayout", &m_codecContext->ch_layout, 0);
|
|
88
|
-
av_opt_set_int(m_swrContext, "in_sample_rate", sampleRate, 0);
|
|
89
|
-
av_opt_set_sample_fmt(m_swrContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
|
|
90
|
-
|
|
91
|
-
av_opt_set_chlayout(m_swrContext, "out_chlayout", &m_codecContext->ch_layout, 0);
|
|
92
|
-
av_opt_set_int(m_swrContext, "out_sample_rate", sampleRate, 0);
|
|
93
|
-
av_opt_set_sample_fmt(m_swrContext, "out_sample_fmt", m_codecContext->sample_fmt, 0);
|
|
94
|
-
|
|
95
|
-
ret = swr_init(m_swrContext);
|
|
96
|
-
if (ret < 0)
|
|
97
|
-
{
|
|
98
|
-
std::cerr << "Could not initialize SWR context" << std::endl;
|
|
99
|
-
cleanup();
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
m_frame = av_frame_alloc();
|
|
103
|
-
if (!m_frame)
|
|
104
|
-
{
|
|
105
|
-
cleanup();
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
m_frame->format = m_codecContext->sample_fmt;
|
|
109
|
-
m_frame->ch_layout = m_codecContext->ch_layout;
|
|
110
|
-
m_frame->sample_rate = m_codecContext->sample_rate;
|
|
111
|
-
m_frame->nb_samples = m_codecContext->frame_size;
|
|
112
|
-
|
|
113
|
-
ret = av_frame_get_buffer(m_frame, 0);
|
|
114
|
-
if (ret < 0)
|
|
115
|
-
{
|
|
116
|
-
std::cerr << "Could not allocate frame buffer" << std::endl;
|
|
117
|
-
cleanup();
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
m_audioFifo = av_audio_fifo_alloc(
|
|
122
|
-
m_codecContext->sample_fmt,
|
|
123
|
-
m_codecContext->ch_layout.nb_channels,
|
|
124
|
-
m_codecContext->frame_size * 2);
|
|
125
|
-
|
|
126
|
-
if (!m_audioFifo)
|
|
127
|
-
{
|
|
128
|
-
std::cerr << "Could not allocate audio FIFO" << std::endl;
|
|
129
|
-
cleanup();
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
if (mode == OutputMode::STANDALONE)
|
|
134
|
-
{
|
|
135
|
-
avformat_alloc_output_context2(&m_formatContext, nullptr, "mpegts", nullptr);
|
|
136
|
-
if (!m_formatContext)
|
|
137
|
-
{
|
|
138
|
-
std::cerr << "Could not create output context for TS" << std::endl;
|
|
139
|
-
cleanup();
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
m_stream = avformat_new_stream(m_formatContext, nullptr);
|
|
144
|
-
if (!m_stream)
|
|
145
|
-
{
|
|
146
|
-
std::cerr << "Could not create audio stream" << std::endl;
|
|
147
|
-
cleanup();
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
avcodec_parameters_from_context(m_stream->codecpar, m_codecContext);
|
|
152
|
-
// Use the same time base as the codec context for simplicity
|
|
153
|
-
m_stream->time_base = m_codecContext->time_base;
|
|
154
|
-
targetChunkDuration = 4.0;
|
|
155
|
-
currentSegmentStartPts = 0;
|
|
156
|
-
currentSegmentDuration = 0.0;
|
|
157
|
-
}
|
|
158
|
-
m_initialized = true;
|
|
159
|
-
return true;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
bool AudioEncoder::encodeSamples(const uint8_t *samples, int numSamples, int64_t pts)
|
|
163
|
-
{
|
|
164
|
-
if (!m_initialized)
|
|
165
|
-
{
|
|
166
|
-
std::cerr << "Encoder is not initialized!" << std::endl;
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
int samplesToEncode = numSamples;
|
|
170
|
-
const uint8_t* samplesToUse = samples;
|
|
171
|
-
if (pts >= 0) {
|
|
172
|
-
if (pts < m_nextInputPts) {
|
|
173
|
-
const int64_t overlap = m_nextInputPts - pts;
|
|
174
|
-
if (overlap >= numSamples) {
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
const int bytesPerFrame = m_channels * static_cast<int>(sizeof(int16_t));
|
|
178
|
-
samplesToUse = samples + (overlap * bytesPerFrame);
|
|
179
|
-
samplesToEncode = static_cast<int>(numSamples - overlap);
|
|
180
|
-
pts = m_nextInputPts;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (pts > m_nextInputPts + m_codecContext->frame_size &&
|
|
184
|
-
av_audio_fifo_size(m_audioFifo) > 0)
|
|
185
|
-
{
|
|
186
|
-
av_audio_fifo_reset(m_audioFifo);
|
|
187
|
-
m_sampleCount = pts;
|
|
188
|
-
} else if (av_audio_fifo_size(m_audioFifo) == 0) {
|
|
189
|
-
m_sampleCount = pts;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (samplesToEncode <= 0) {
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
uint8_t **resampledData = nullptr;
|
|
198
|
-
int linesize;
|
|
199
|
-
int resampledSamples = av_samples_alloc_array_and_samples(
|
|
200
|
-
&resampledData,
|
|
201
|
-
&linesize,
|
|
202
|
-
m_codecContext->ch_layout.nb_channels,
|
|
203
|
-
samplesToEncode,
|
|
204
|
-
m_codecContext->sample_fmt,
|
|
205
|
-
0);
|
|
206
|
-
if (resampledSamples < 0)
|
|
207
|
-
{
|
|
208
|
-
std::cerr << "Could not allocate resampled buffer" << std::endl;
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
const uint8_t *inputData[1] = {samplesToUse};
|
|
212
|
-
int outputSamples = swr_convert(
|
|
213
|
-
m_swrContext,
|
|
214
|
-
resampledData,
|
|
215
|
-
samplesToEncode,
|
|
216
|
-
inputData,
|
|
217
|
-
samplesToEncode);
|
|
218
|
-
|
|
219
|
-
if (outputSamples < 0)
|
|
220
|
-
{
|
|
221
|
-
av_freep(&resampledData[0]);
|
|
222
|
-
av_freep(&resampledData);
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
av_audio_fifo_write(m_audioFifo, (void **)resampledData, outputSamples);
|
|
227
|
-
while (av_audio_fifo_size(m_audioFifo) >= m_codecContext->frame_size)
|
|
228
|
-
{
|
|
229
|
-
av_frame_make_writable(m_frame);
|
|
230
|
-
av_audio_fifo_read(m_audioFifo, (void **)m_frame->data, m_codecContext->frame_size);
|
|
231
|
-
m_frame->pts = m_sampleCount;
|
|
232
|
-
m_pts = m_frame->pts;
|
|
233
|
-
|
|
234
|
-
int ret = avcodec_send_frame(m_codecContext, m_frame);
|
|
235
|
-
if (ret < 0)
|
|
236
|
-
{
|
|
237
|
-
std::cerr << "Error sending frame to encoder" << std::endl;
|
|
238
|
-
av_freep(&resampledData[0]);
|
|
239
|
-
av_freep(&resampledData);
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
while (ret >= 0)
|
|
244
|
-
{
|
|
245
|
-
AVPacket *packet = av_packet_alloc();
|
|
246
|
-
ret = avcodec_receive_packet(m_codecContext, packet);
|
|
247
|
-
|
|
248
|
-
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
|
249
|
-
{
|
|
250
|
-
av_packet_free(&packet);
|
|
251
|
-
break;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (mode == OutputMode::MUXED)
|
|
255
|
-
{
|
|
256
|
-
m_packetQueue.push(packet);
|
|
257
|
-
}
|
|
258
|
-
else if (mode == OutputMode::STANDALONE)
|
|
259
|
-
{
|
|
260
|
-
if (shouldStartNewChunk() || currentChunkIndex == 0)
|
|
261
|
-
{
|
|
262
|
-
// Close current chunk if exists
|
|
263
|
-
if (m_formatContext && m_formatContext->pb)
|
|
264
|
-
{
|
|
265
|
-
av_write_trailer(m_formatContext);
|
|
266
|
-
avio_closep(&m_formatContext->pb);
|
|
267
|
-
|
|
268
|
-
currentSegmentDuration = (m_pts - currentSegmentStartPts) * av_q2d(m_codecContext->time_base);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Generate filename for new chunk
|
|
272
|
-
std::ostringstream filename;
|
|
273
|
-
filename << "audio_chunk" << std::setfill('0') << std::setw(3) << currentChunkIndex << ".ts";
|
|
274
|
-
std::string chunkFilename = filename.str();
|
|
275
|
-
m_chunkFileNames.push_back(chunkFilename);
|
|
276
|
-
|
|
277
|
-
// Open new chunk file
|
|
278
|
-
if (avio_open(&m_formatContext->pb, chunkFilename.c_str(), AVIO_FLAG_WRITE) < 0)
|
|
279
|
-
{
|
|
280
|
-
std::cerr << "Could not open output file: " << chunkFilename << std::endl;
|
|
281
|
-
av_packet_free(&packet);
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Write header for new chunk
|
|
286
|
-
if (avformat_write_header(m_formatContext, nullptr) < 0)
|
|
287
|
-
{
|
|
288
|
-
std::cerr << "Could not write header for new chunk" << std::endl;
|
|
289
|
-
av_packet_free(&packet);
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
currentChunkIndex++;
|
|
294
|
-
currentSegmentStartPts = m_pts;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// Write packet to current chunk
|
|
298
|
-
packet->stream_index = m_stream->index;
|
|
299
|
-
av_packet_rescale_ts(packet, m_codecContext->time_base, m_stream->time_base);
|
|
300
|
-
if (av_interleaved_write_frame(m_formatContext, packet) < 0)
|
|
301
|
-
{
|
|
302
|
-
std::cerr << "Failed to write audio packet" << std::endl;
|
|
303
|
-
}
|
|
304
|
-
av_packet_free(&packet);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
m_sampleCount += m_codecContext->frame_size;
|
|
308
|
-
}
|
|
309
|
-
if (pts >= 0) {
|
|
310
|
-
m_nextInputPts = std::max<int64_t>(m_nextInputPts, pts + samplesToEncode);
|
|
311
|
-
} else {
|
|
312
|
-
m_nextInputPts = std::max<int64_t>(m_nextInputPts, m_sampleCount);
|
|
313
|
-
}
|
|
314
|
-
av_freep(&resampledData[0]);
|
|
315
|
-
av_freep(&resampledData);
|
|
316
|
-
|
|
317
|
-
return true;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
bool AudioEncoder::hasPackets() const
|
|
321
|
-
{
|
|
322
|
-
return !m_packetQueue.empty();
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
AVPacket *AudioEncoder::getNextPacket()
|
|
326
|
-
{
|
|
327
|
-
if (m_packetQueue.empty())
|
|
328
|
-
{
|
|
329
|
-
return nullptr;
|
|
330
|
-
}
|
|
331
|
-
AVPacket *packet = m_packetQueue.front();
|
|
332
|
-
m_packetQueue.pop();
|
|
333
|
-
return packet;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
bool AudioEncoder::shouldStartNewChunk() const
|
|
337
|
-
{
|
|
338
|
-
double duration = (m_pts - currentSegmentStartPts) * av_q2d(m_codecContext->time_base);
|
|
339
|
-
return duration >= targetChunkDuration;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
void AudioEncoder::forceNewChunk()
|
|
343
|
-
{
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
void AudioEncoder::cleanup()
|
|
347
|
-
{
|
|
348
|
-
// Flush encoder to get remaining packets
|
|
349
|
-
if (m_initialized && m_codecContext)
|
|
350
|
-
{
|
|
351
|
-
flushEncoder();
|
|
352
|
-
|
|
353
|
-
// Finalize last segment if in STANDALONE mode
|
|
354
|
-
if (mode == OutputMode::STANDALONE && m_formatContext && m_formatContext->pb)
|
|
355
|
-
{
|
|
356
|
-
// Update duration for the final segment
|
|
357
|
-
currentSegmentDuration = (m_pts - currentSegmentStartPts) * av_q2d(m_codecContext->time_base);
|
|
358
|
-
|
|
359
|
-
av_write_trailer(m_formatContext);
|
|
360
|
-
avio_closep(&m_formatContext->pb);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
if (mode != OutputMode::MUXED)
|
|
365
|
-
{
|
|
366
|
-
while (!m_packetQueue.empty())
|
|
367
|
-
{
|
|
368
|
-
AVPacket *pkt = m_packetQueue.front();
|
|
369
|
-
m_packetQueue.pop();
|
|
370
|
-
av_packet_free(&pkt);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
if (m_audioFifo)
|
|
374
|
-
{
|
|
375
|
-
av_audio_fifo_free(m_audioFifo);
|
|
376
|
-
m_audioFifo = nullptr;
|
|
377
|
-
}
|
|
378
|
-
if (m_frame)
|
|
379
|
-
{
|
|
380
|
-
av_frame_free(&m_frame);
|
|
381
|
-
m_frame = nullptr;
|
|
382
|
-
}
|
|
383
|
-
if (m_swrContext)
|
|
384
|
-
{
|
|
385
|
-
swr_free(&m_swrContext);
|
|
386
|
-
m_swrContext = nullptr;
|
|
387
|
-
}
|
|
388
|
-
if (m_formatContext)
|
|
389
|
-
{
|
|
390
|
-
if (m_formatContext->pb)
|
|
391
|
-
{
|
|
392
|
-
// Should already be closed above, but ensure it's closed
|
|
393
|
-
avio_closep(&m_formatContext->pb);
|
|
394
|
-
}
|
|
395
|
-
avformat_free_context(m_formatContext);
|
|
396
|
-
m_formatContext = nullptr;
|
|
397
|
-
}
|
|
398
|
-
if (m_codecContext)
|
|
399
|
-
{
|
|
400
|
-
avcodec_free_context(&m_codecContext);
|
|
401
|
-
m_codecContext = nullptr;
|
|
402
|
-
}
|
|
403
|
-
m_initialized = false;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
std::string AudioEncoder::generatePlaylist() const
|
|
407
|
-
{
|
|
408
|
-
if (mode != OutputMode::STANDALONE || m_chunkFileNames.empty())
|
|
409
|
-
{
|
|
410
|
-
return "";
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
std::string playlist = "#EXTM3U\n";
|
|
414
|
-
playlist += "#EXT-X-VERSION:3\n";
|
|
415
|
-
playlist += "#EXT-X-TARGETDURATION:" + std::to_string(static_cast<int>(targetChunkDuration + 1)) + "\n";
|
|
416
|
-
playlist += "#EXT-X-MEDIA-SEQUENCE:0\n";
|
|
417
|
-
|
|
418
|
-
for (size_t i = 0; i < m_chunkFileNames.size(); ++i)
|
|
419
|
-
{
|
|
420
|
-
double duration = targetChunkDuration;
|
|
421
|
-
if (i == m_chunkFileNames.size() - 1 && currentSegmentDuration > 0)
|
|
422
|
-
{
|
|
423
|
-
duration = currentSegmentDuration; // Last segment might be shorter
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
playlist += "#EXTINF:" + std::to_string(duration) + ",\n";
|
|
427
|
-
playlist += m_chunkFileNames[i] + "\n";
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// Add end marker if encoding is complete
|
|
431
|
-
if (!m_initialized)
|
|
432
|
-
{
|
|
433
|
-
playlist += "#EXT-X-ENDLIST\n";
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return playlist;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// Drain encoder and handle remaining packets based on mode
|
|
440
|
-
void AudioEncoder::flushEncoder()
|
|
441
|
-
{
|
|
442
|
-
if (!m_codecContext)
|
|
443
|
-
return;
|
|
444
|
-
|
|
445
|
-
// Send NULL frame to signal flushing
|
|
446
|
-
int ret = avcodec_send_frame(m_codecContext, nullptr);
|
|
447
|
-
if (ret < 0 && ret != AVERROR_EOF)
|
|
448
|
-
return;
|
|
449
|
-
|
|
450
|
-
while (true)
|
|
451
|
-
{
|
|
452
|
-
AVPacket *packet = av_packet_alloc();
|
|
453
|
-
ret = avcodec_receive_packet(m_codecContext, packet);
|
|
454
|
-
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
|
455
|
-
{
|
|
456
|
-
av_packet_free(&packet);
|
|
457
|
-
break;
|
|
458
|
-
}
|
|
459
|
-
if (ret < 0)
|
|
460
|
-
{
|
|
461
|
-
av_packet_free(&packet);
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
if (mode == OutputMode::MUXED)
|
|
466
|
-
{
|
|
467
|
-
m_packetQueue.push(packet);
|
|
468
|
-
}
|
|
469
|
-
else if (mode == OutputMode::STANDALONE && m_formatContext && m_formatContext->pb)
|
|
470
|
-
{
|
|
471
|
-
packet->stream_index = m_stream->index;
|
|
472
|
-
av_packet_rescale_ts(packet, m_codecContext->time_base, m_stream->time_base);
|
|
473
|
-
if (av_interleaved_write_frame(m_formatContext, packet) < 0)
|
|
474
|
-
{
|
|
475
|
-
std::cerr << "Failed to write flushed audio packet" << std::endl;
|
|
476
|
-
}
|
|
477
|
-
av_packet_free(&packet);
|
|
478
|
-
}
|
|
479
|
-
else
|
|
480
|
-
{
|
|
481
|
-
av_packet_free(&packet);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|