-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy pathOutputStream.cpp
More file actions
130 lines (113 loc) · 4.46 KB
/
Copy pathOutputStream.cpp
File metadata and controls
130 lines (113 loc) · 4.46 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
#include "OutputStream.hpp"
#include <AvTranscoder/file/OutputFile.hpp>
#include <cassert>
namespace avtranscoder
{
OutputStream::OutputStream(OutputFile& outputFile, const size_t streamIndex)
: IOutputStream()
, _outputFile(outputFile)
, _outputAVStream(outputFile.getFormatContext().getAVStream(streamIndex))
, _codecContext()
, _streamIndex(streamIndex)
, _wrappedPacketsDuration(0)
, _lastWrappedPacketDuration(0)
, _isPTSGenerated(false)
{
const AVCodec* codec = avcodec_find_encoder(_outputAVStream.codecpar->codec_id);
_codecContext = avcodec_alloc_context3(codec);
int ret = avcodec_parameters_to_context(_codecContext, _outputAVStream.codecpar);
if (ret < 0)
throw std::runtime_error("Failed to copy encoder parameters to output stream context");
#if LIBAVCODEC_VERSION_MAJOR > 58
// depending on the format, place global headers in extradata instead of every keyframe
#ifdef AV_CODEC_FLAG_GLOBAL_HEADER
if(_outputFile.getFormatContext().getAVOutputFormat().flags & AVFMT_GLOBALHEADER)
{
_codecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
#endif
// if the codec is experimental, allow it
#ifdef AV_CODEC_CAP_EXPERIMENTAL
if(codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
{
LOG_WARN("This codec is considered experimental by libav/ffmpeg:" << codec->name);
_codecContext->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
}
#endif
#endif
}
float OutputStream::getStreamDuration() const
{
const AVRational& outputTimeBase = _outputAVStream.time_base;
// check floating point exception
if(outputTimeBase.den == 0)
{
LOG_WARN("Cannot compute stream duration of output stream at index " << _streamIndex)
return 0.f;
}
if(_wrappedPacketsDuration)
return av_q2d(outputTimeBase) * _wrappedPacketsDuration;
#if AVTRANSCODER_FFMPEG_DEPENDENCY && LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 40, 100)
// returns the pts of the last muxed packet, converted from timebase to seconds
return av_q2d(outputTimeBase) * av_stream_get_end_pts(&_outputAVStream);
#else
return av_q2d(outputTimeBase) * _outputAVStream.pts;
#endif
}
size_t OutputStream::getNbFrames() const
{
return _outputAVStream.nb_frames;
}
// int OutputStream::getStreamPTS() const
// {
// // const AVFrac& outputPTS = _outputAVStream.pts;
// // return (outputPTS.val + (outputPTS.num / outputPTS.den));
// return _outputAVStream.pts;
// }
IOutputStream::EWrappingStatus OutputStream::wrap(const CodedData& data)
{
// If stream PTS will be generated at rewrap time
if(!_isPTSGenerated && (data.getAVPacket().pts == 0 || data.getAVPacket().pts == AV_NOPTS_VALUE) &&
data.getAVPacket().dts == AV_NOPTS_VALUE)
{
LOG_WARN("PTS of output stream " << _streamIndex << " is generated at rewrap time.")
_isPTSGenerated = true;
}
// wrap packet
IOutputStream::EWrappingStatus status = _outputFile.wrap(data, _streamIndex);
// Store duration of the last packet wrapped
if(data.getAVPacket().duration != 0 && data.getAVPacket().duration != _lastWrappedPacketDuration)
_lastWrappedPacketDuration = data.getAVPacket().duration;
// Append duration of the packet to the stream
if(data.getAVPacket().duration)
_wrappedPacketsDuration += data.getAVPacket().duration;
else
{
switch(_outputAVStream.codecpar->codec_type)
{
case AVMEDIA_TYPE_VIDEO:
{
_wrappedPacketsDuration += _lastWrappedPacketDuration;
break;
}
case AVMEDIA_TYPE_AUDIO:
{
Rational audioPacketDuration;
audioPacketDuration.num = 0;
audioPacketDuration.den = 0;
const int frame_size = av_get_audio_frame_duration(_codecContext, data.getSize());
if (frame_size <= 0 || _outputAVStream.codecpar->sample_rate <= 0)
break;
audioPacketDuration.num = frame_size;
audioPacketDuration.den = _outputAVStream.codecpar->sample_rate;
_wrappedPacketsDuration += av_rescale(1, audioPacketDuration.num * (int64_t) _outputAVStream.time_base.den * _codecContext->ticks_per_frame,
audioPacketDuration.den * (int64_t) _outputAVStream.time_base.num);
break;
}
default:
break;
}
}
return status;
}
}