2
#include "FFmpegDecoder.hpp"
3
#include "FFmpegParameters.hpp"
6
#include <osgDB/FileNameUtils>
14
// Changes for FFMpeg version greater than 0.6
15
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0)
16
#define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO
17
#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO
21
#define AVERROR_IO AVERROR(EIO)
22
#define AVERROR_NUMEXPECTED AVERROR(EDOM)
23
#define AVERROR_NOMEM AVERROR(ENOMEM)
24
#define AVERROR_NOFMT AVERROR(EILSEQ)
25
#define AVERROR_NOTSUPP AVERROR(ENOSYS)
26
#define AVERROR_NOENT AVERROR(ENOENT)
31
static std::string AvStrError(int errnum)
34
av_strerror(errnum, buf, sizeof(buf));
35
return std::string(buf);
38
FFmpegDecoder::FFmpegDecoder() :
43
m_audio_decoder(m_audio_queue, m_clocks),
44
m_video_decoder(m_video_queue, m_clocks),
53
FFmpegDecoder::~FFmpegDecoder()
59
bool FFmpegDecoder::open(const std::string & filename, FFmpegParameters* parameters)
64
AVFormatContext * p_format_context = 0;
66
if (filename.compare(0, 5, "/dev/")==0)
69
throw std::runtime_error("Device not supported on Android");
71
avdevice_register_all();
73
OSG_NOTICE<<"Attempting to stream "<<filename<<std::endl;
75
AVInputFormat *iformat;
77
av_dict_set(parameters->getOptions(), "video_size", "320x240", 0);
79
av_dict_set(parameters->getOptions(), "video_size", "640x480", 0);
81
av_dict_set(parameters->getOptions(), "framerate", "1:30", 0);
83
std::string format = "video4linux2";
84
iformat = av_find_input_format(format.c_str());
88
OSG_NOTICE<<"Found input format: "<<format<<std::endl;
92
OSG_NOTICE<<"Failed to find input format: "<<format<<std::endl;
95
int error = avformat_open_input(&p_format_context, filename.c_str(), iformat, parameters->getOptions());
98
std::string error_str;
101
//case AVERROR_UNKNOWN: error_str = "AVERROR_UNKNOWN"; break; // same value as AVERROR_INVALIDDATA
102
case AVERROR_IO: error_str = "AVERROR_IO"; break;
103
case AVERROR_NUMEXPECTED: error_str = "AVERROR_NUMEXPECTED"; break;
104
case AVERROR_INVALIDDATA: error_str = "AVERROR_INVALIDDATA"; break;
105
case AVERROR_NOMEM: error_str = "AVERROR_NOMEM"; break;
106
case AVERROR_NOFMT: error_str = "AVERROR_NOFMT"; break;
107
case AVERROR_NOTSUPP: error_str = "AVERROR_NOTSUPP"; break;
108
case AVERROR_NOENT: error_str = "AVERROR_NOENT"; break;
109
case AVERROR_PATCHWELCOME: error_str = "AVERROR_PATCHWELCOME"; break;
110
default: error_str = "Unknown error"; break;
113
throw std::runtime_error("av_open_input_file() failed : " + error_str);
119
AVInputFormat* iformat = (parameters ? parameters->getFormat() : 0);
120
AVIOContext* context = parameters->getContext();
123
p_format_context = avformat_alloc_context();
124
p_format_context->pb = context;
126
if (avformat_open_input(&p_format_context, filename.c_str(), iformat, parameters->getOptions()) != 0)
127
throw std::runtime_error("av_open_input_file() failed");
130
m_format_context.reset(p_format_context);
132
// Retrieve stream info
133
// Only buffer up to one and a half seconds
134
p_format_context->max_analyze_duration = AV_TIME_BASE * 1.5f;
135
if (avformat_find_stream_info(p_format_context, NULL) < 0)
136
throw std::runtime_error("av_find_stream_info() failed");
138
m_duration = double(m_format_context->duration) / AV_TIME_BASE;
139
if (m_format_context->start_time != AV_NOPTS_VALUE)
140
m_start = double(m_format_context->start_time) / AV_TIME_BASE;
144
// TODO move this elsewhere
145
m_clocks.reset(m_start);
147
// Dump info to stderr
148
av_dump_format(p_format_context, 0, filename.c_str(), false);
150
// Find and open the first video and audio streams (note that audio stream is optional and only opened if possible)
151
if ((m_video_index = av_find_best_stream(m_format_context.get(), AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0)) < 0)
152
throw std::runtime_error("Could not open video stream");
153
m_video_stream = m_format_context->streams[m_video_index];
155
if ((m_audio_index = av_find_best_stream(m_format_context.get(), AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0)) >= 0)
156
m_audio_stream = m_format_context->streams[m_audio_index];
160
m_audio_index = std::numeric_limits<unsigned int>::max();
163
m_video_decoder.open(m_video_stream);
167
m_audio_decoder.open(m_audio_stream);
170
catch (const std::runtime_error & error)
172
OSG_WARN << "FFmpegImageStream::open audio failed, audio stream will be disabled: " << error.what() << std::endl;
176
catch (const std::runtime_error & error)
178
OSG_WARN << "FFmpegImageStream::open : " << error.what() << std::endl;
187
void FFmpegDecoder::close(bool waitForThreadToExit)
192
m_audio_decoder.close(waitForThreadToExit);
193
m_video_decoder.close(waitForThreadToExit);
198
bool FFmpegDecoder::readNextPacket()
203
return readNextPacketNormal();
209
return readNextPacketEndOfStream();
212
return readNextPacketRewinding();
215
return readNextPacketSeeking();
218
OSG_FATAL << "unknown decoder state " << m_state << std::endl;
226
void FFmpegDecoder::rewind()
228
m_pending_packet.clear();
232
rewindButDontFlushQueues();
235
void FFmpegDecoder::seek(double time)
237
m_pending_packet.clear();
241
seekButDontFlushQueues(time);
244
void FFmpegDecoder::pause()
246
m_pending_packet.clear();
254
inline void FFmpegDecoder::flushAudioQueue()
256
FFmpegPacketClear pc;
257
m_audio_queue.flush(pc);
262
inline void FFmpegDecoder::flushVideoQueue()
264
FFmpegPacketClear pc;
265
m_video_queue.flush(pc);
270
bool FFmpegDecoder::readNextPacketNormal()
274
if (! m_pending_packet)
276
bool end_of_stream = false;
278
// Read the next frame packet
279
int error = av_read_frame(m_format_context.get(), &packet);
282
if (error == AVERROR_EOF || url_feof(m_format_context.get()->pb))
283
end_of_stream = true;
285
OSG_FATAL << "av_read_frame() returned " << AvStrError(error) << std::endl;
286
throw std::runtime_error("av_read_frame() failed");
292
// If we reach the end of the stream, change the decoder state
295
m_clocks.reset(m_start);
296
rewindButDontFlushQueues();
299
m_state = END_OF_STREAM;
305
// Make the packet data available beyond av_read_frame() logical scope.
306
if ((error = av_dup_packet(&packet)) < 0) {
307
OSG_FATAL << "av_dup_packet() returned " << AvStrError(error) << std::endl;
308
throw std::runtime_error("av_dup_packet() failed");
311
m_pending_packet = FFmpegPacket(packet);
316
if (m_pending_packet.type == FFmpegPacket::PACKET_DATA)
318
if (m_pending_packet.packet.stream_index == m_audio_index)
320
if (m_audio_queue.timedPush(m_pending_packet, 10)) {
321
m_pending_packet.release();
325
else if (m_pending_packet.packet.stream_index == m_video_index)
327
if (m_video_queue.timedPush(m_pending_packet, 10)) {
328
m_pending_packet.release();
334
m_pending_packet.clear();
344
bool FFmpegDecoder::readNextPacketEndOfStream()
346
const FFmpegPacket packet(FFmpegPacket::PACKET_END_OF_STREAM);
348
m_audio_queue.timedPush(packet, 10);
349
m_video_queue.timedPush(packet, 10);
356
bool FFmpegDecoder::readNextPacketRewinding()
358
const FFmpegPacket packet(FFmpegPacket::PACKET_FLUSH);
360
if (m_audio_queue.timedPush(packet, 10) && m_video_queue.timedPush(packet, 10))
368
void FFmpegDecoder::rewindButDontFlushQueues()
370
const AVRational AvTimeBaseQ = { 1, AV_TIME_BASE }; // = AV_TIME_BASE_Q
372
const int64_t pos = int64_t(m_clocks.getStartTime() * double(AV_TIME_BASE));
373
const int64_t seek_target = av_rescale_q(pos, AvTimeBaseQ, m_video_stream->time_base);
376
if ((error = av_seek_frame(m_format_context.get(), m_video_index, seek_target, 0/*AVSEEK_FLAG_BYTE |*/ /*AVSEEK_FLAG_BACKWARD*/)) < 0) {
377
OSG_FATAL << "av_seek_frame returned " << AvStrError(error) << std::endl;
378
throw std::runtime_error("av_seek_frame failed()");
385
bool FFmpegDecoder::readNextPacketSeeking()
387
const FFmpegPacket packet(FFmpegPacket::PACKET_FLUSH);
389
if (m_audio_queue.timedPush(packet, 10) && m_video_queue.timedPush(packet, 10))
395
void FFmpegDecoder::seekButDontFlushQueues(double time)
397
const AVRational AvTimeBaseQ = { 1, AV_TIME_BASE }; // = AV_TIME_BASE_Q
399
const int64_t pos = int64_t(m_clocks.getStartTime()+time * double(AV_TIME_BASE));
400
const int64_t seek_target = av_rescale_q(pos, AvTimeBaseQ, m_video_stream->time_base);
402
m_clocks.setSeekTime(time);
405
if ((error = av_seek_frame(m_format_context.get(), m_video_index, seek_target, 0/*AVSEEK_FLAG_BYTE |*/ /*AVSEEK_FLAG_BACKWARD*/)) < 0) {
406
OSG_FATAL << "av_seek_frame() returned " << AvStrError(error) << std::endl;
407
throw std::runtime_error("av_seek_frame failed()");
416
} // namespace osgFFmpeg