-
Notifications
You must be signed in to change notification settings - Fork 3
/
muxer.cpp
80 lines (63 loc) · 2.89 KB
/
muxer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include "muxer.h"
// Custom writing avio https://ffmpeg.org/pipermail/ffmpeg-devel/2014-November/165014.html
static int write_packet(void* opaque, uint8_t* buf, int buf_size) {
auto writer = *reinterpret_cast<val*>(opaque);
auto data = val(typed_memory_view(buf_size, buf));
writer.call<void>("write", data);
return buf_size;
}
static int64_t seek_for_write(void* opaque, int64_t pos, int whence) {
auto writer = *reinterpret_cast<val*>(opaque);
switch (whence) {
case SEEK_SET:
writer.call<val>("seek", (double)pos); break;
case SEEK_CUR:
pos += (int64_t)writer["offset"].as<double>();
writer.call<val>("seek", (double)pos); break;
default:
CHECK(false, "cannot process seek_for_read");
}
return pos;
}
Muxer::Muxer(string format, val _writer) {
writer = std::move(_writer); // writer will be destroyed at end of this function
auto writerPtr = reinterpret_cast<void*>(&writer);
// create buffer for writing
auto buffer = (uint8_t*)av_malloc(buf_size);
io_ctx = avio_alloc_context(buffer, buf_size, 1, writerPtr, NULL, write_packet, seek_for_write);
avformat_alloc_output_context2(&format_ctx, NULL, format.c_str(), NULL);
CHECK(format_ctx != NULL, "Could not create output format context");
format_ctx->pb = io_ctx;
format_ctx->flags |= AVFMT_FLAG_CUSTOM_IO;
}
InferredFormatInfo Muxer::inferFormatInfo(string format_name, string filename) {
auto format = av_guess_format(format_name.c_str(), filename.c_str(), NULL);
if (format == NULL)
// maybe format_name is extension of the filename
format = av_guess_format("", (filename + "." + format_name).c_str(), NULL);
auto video_codec = avcodec_find_encoder(format->video_codec);
auto audio_codec = avcodec_find_encoder(format->audio_codec);
InferredStreamInfo videoInfo = {
.codec_name = video_codec->name,
.format = av_get_pix_fmt_name(*video_codec->pix_fmts),
};
InferredStreamInfo audioInfo = {
.codec_name = audio_codec->name,
.format = av_get_sample_fmt_name(*audio_codec->sample_fmts)
};
return {
.format = format->name,
.video = videoInfo,
.audio = audioInfo };
}
void Muxer::writeFrame(Packet* packet, int stream_i) {
auto av_pkt = packet->av_packet();
CHECK(stream_i >= 0 && stream_i < streams.size(), "stream_index of packet not in valid streams");
auto av_stream = streams[stream_i]->av_stream_ptr();
// rescale packet from encoder to muxer stream
CHECK(stream_i >= 0 && stream_i < from_time_bases.size(), "stream_index of packet not in valid from_time_bases");
av_packet_rescale_ts(av_pkt, from_time_bases[stream_i], av_stream->time_base);
av_pkt->stream_index = stream_i;
int ret = av_interleaved_write_frame(format_ctx, av_pkt);
CHECK(ret >= 0, "interleave write frame error");
}