-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathdemuxer.cpp
More file actions
154 lines (113 loc) · 5.21 KB
/
demuxer.cpp
File metadata and controls
154 lines (113 loc) · 5.21 KB
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#include "demuxer.h"
#include <iostream>
#include "ffmpeg.h"
#include "string_utils.h"
Demuxer::Demuxer(const Side& side, const std::string& demuxer_name, const std::string& file_name, AVDictionary* demuxer_options, const AVDictionary* decoder_options) : SideAware(side) {
ScopedLogSide scoped_log_side(side);
const AVInputFormat* input_format = nullptr;
if (!demuxer_name.empty()) {
input_format = av_find_input_format(demuxer_name.c_str());
if (input_format == nullptr) {
throw std::runtime_error(file_name + ": Demuxer '" + demuxer_name + "' not found");
}
}
ffmpeg::check(file_name, avformat_open_input(&format_context_, file_name.c_str(), const_cast<AVInputFormat*>(input_format), &demuxer_options));
ffmpeg::check_dict_is_empty(demuxer_options, string_sprintf("Demuxer %s", format_name().c_str()));
// Try to find best stream first
video_stream_index_ = av_find_best_stream(format_context_, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
const unsigned int nb_streams_before = format_context_->nb_streams;
AVDictionary** opts_for_streams = (AVDictionary**)av_calloc(nb_streams_before, sizeof(AVDictionary*));
// User-specified options are only used if we have a valid video stream index
if (video_stream_index_ >= 0) {
av_dict_copy(&opts_for_streams[video_stream_index_], decoder_options, 0);
}
// Achtung: avformat_find_stream_info() may modify the copied options
ffmpeg::check(file_name, avformat_find_stream_info(format_context_, opts_for_streams));
if (format_context_->nb_streams == 0) {
throw std::runtime_error(file_name + ": No streams found in container");
}
if (video_stream_index_ < 0) {
// Try manual search for video stream
for (unsigned int i = 0; i < format_context_->nb_streams; i++) {
const AVStream* stream = format_context_->streams[i];
if (stream != nullptr && stream->codecpar != nullptr && stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index_ = i;
break;
}
}
if (video_stream_index_ < 0) {
throw std::runtime_error(file_name + ": No video stream found");
}
}
for (unsigned int i = 0; i < nb_streams_before; i++) {
av_dict_free(&opts_for_streams[i]);
}
av_freep(&opts_for_streams);
}
Demuxer::~Demuxer() {
avformat_close_input(&format_context_);
}
AVCodecParameters* Demuxer::video_codec_parameters() {
return format_context_->streams[video_stream_index_]->codecpar;
}
int Demuxer::video_stream_index() const {
return video_stream_index_;
}
AVRational Demuxer::time_base() const {
return format_context_->streams[video_stream_index_]->time_base;
}
int64_t Demuxer::duration() const {
// use stream duration if available, otherwise use container duration if available, else 0
const int64_t stream_duration = format_context_->streams[video_stream_index_]->duration;
return stream_duration != AV_NOPTS_VALUE ? av_rescale_q(stream_duration, time_base(), AV_R_MICROSECONDS) : (format_context_->duration != AV_NOPTS_VALUE ? format_context_->duration : 0);
}
int64_t Demuxer::start_time() const {
return format_context_->start_time != AV_NOPTS_VALUE ? format_context_->start_time : 0;
}
int Demuxer::rotation() const {
double theta = 0;
AVStream* stream = format_context_->streams[video_stream_index_];
#if LIBAVFORMAT_VERSION_MAJOR >= 62
const AVPacketSideData* side_data = av_packet_side_data_get(stream->codecpar->coded_side_data, stream->codecpar->nb_coded_side_data, AV_PKT_DATA_DISPLAYMATRIX);
// require 9 integers (3x3 matrix) + allow hypothetical padding
if (side_data != nullptr && side_data->data != nullptr && side_data->size >= int(9 * sizeof(int32_t))) {
theta = -av_display_rotation_get(reinterpret_cast<const int32_t*>(side_data->data));
}
#else
uint8_t* displaymatrix = av_stream_get_side_data(stream, AV_PKT_DATA_DISPLAYMATRIX, nullptr);
if (displaymatrix != nullptr) {
theta = -av_display_rotation_get(reinterpret_cast<int32_t*>(displaymatrix));
}
#endif
theta -= 360 * floor(theta / 360 + 0.9 / 360);
return theta;
}
AVRational Demuxer::guess_frame_rate(AVFrame* frame) const {
return av_guess_frame_rate(format_context_, format_context_->streams[video_stream_index_], frame);
}
AVRational Demuxer::sample_aspect_ratio(AVFrame* frame) const {
AVStream* stream = format_context_->streams[video_stream_index_];
if (stream == nullptr) {
return AVRational{0, 1};
}
return av_guess_sample_aspect_ratio(format_context_, stream, frame);
}
bool Demuxer::operator()(AVPacket& packet) {
return av_read_frame(format_context_, &packet) >= 0;
}
bool Demuxer::seek(const float position, const bool backward) {
ScopedLogSide scoped_log_side(get_side());
int64_t seek_target = static_cast<int64_t>(position * AV_TIME_BASE);
return av_seek_frame(format_context_, -1, seek_target, backward ? AVSEEK_FLAG_BACKWARD : 0) >= 0;
}
std::string Demuxer::format_name() {
return format_context_->iformat->name;
}
int64_t Demuxer::file_size() {
return avio_size(format_context_->pb);
}
int64_t Demuxer::bit_rate() {
// use stream bit rate if available, otherwise use container bit rate
const int64_t stream_bit_rate = format_context_->streams[video_stream_index_]->codecpar->bit_rate;
return stream_bit_rate > 0 ? stream_bit_rate : format_context_->bit_rate;
}