AVPacket* Stream::popEncodedData() { AVPacket* result = nullptr; sf::Lock l(m_readerMutex); if (!m_packetList.size() && !isPassive()) { m_dataSource.requestMoreData(*this); } if (m_packetList.size()) { result = m_packetList.front(); m_packetList.pop_front(); } else { if (m_stream->codec->codec->capabilities & CODEC_CAP_DELAY) { AVPacket* flushPacket = (AVPacket*)av_malloc(sizeof(*flushPacket)); av_init_packet(flushPacket); flushPacket->data = nullptr; flushPacket->size = 0; result = flushPacket; sfeLogDebug("Sending flush packet: " + mediaTypeToString(getStreamKind())); } } return result; }
bool SubtitleStream::onGetData() { AVPacket* packet = popEncodedData(); AVSubtitle sub; int32_t gotSub = 0; uint32_t goOn = 0; int64_t pts = 0; if (packet) { goOn = 1; while (!gotSub && packet && goOn) { bool needsMoreDecoding = false; CHECK(packet != nullptr, "inconsistency error"); goOn = avcodec_decode_subtitle2(m_stream->codec, &sub, &gotSub, packet); pts = 0; if (packet->pts != AV_NOPTS_VALUE) pts = packet->pts; if (gotSub && pts) { bool succeeded = false; std::shared_ptr<SubtitleData> sfeSub = std::make_shared<SubtitleData>(&sub, succeeded); if (succeeded) m_pendingSubtitles.push_back(sfeSub); } if (needsMoreDecoding) { prependEncodedData(packet); } else { av_free_packet(packet); av_free(packet); } if (!gotSub && goOn) { sfeLogDebug("no subtitle in this packet, reading further"); packet = popEncodedData(); } } } return (goOn != 0); }
Demuxer::Demuxer(const std::string& sourceFile, std::shared_ptr<Timer> timer, VideoStream::Delegate& videoDelegate, SubtitleStream::Delegate& subtitleDelegate) : m_formatCtx(nullptr), m_eofReached(false), m_streams(), m_ignoredStreams(), m_synchronized(), m_timer(timer), m_connectedAudioStream(nullptr), m_connectedVideoStream(nullptr), m_connectedSubtitleStream(nullptr), m_duration(sf::Time::Zero) { CHECK(sourceFile.size(), "Demuxer::Demuxer() - invalid argument: sourceFile"); CHECK(timer, "Inconsistency error: null timer"); int err = 0; // Load all the decoders loadFFmpeg(); // Open the movie file err = avformat_open_input(&m_formatCtx, sourceFile.c_str(), nullptr, nullptr); CHECK0(err, "Demuxer::Demuxer() - error while opening media: " + sourceFile); CHECK(m_formatCtx, "Demuxer() - inconsistency: media context cannot be nullptr"); // Read the general movie informations err = avformat_find_stream_info(m_formatCtx, nullptr); CHECK0(err, "Demuxer::Demuxer() - error while retreiving media information"); // Get the media duration if possible (otherwise rely on the streams) if (m_formatCtx->duration != AV_NOPTS_VALUE) { int64_t secs, us; secs = m_formatCtx->duration / AV_TIME_BASE; us = m_formatCtx->duration % AV_TIME_BASE; m_duration = sf::seconds(secs + (float)us / AV_TIME_BASE); } // Find all interesting streams for (unsigned int i = 0; i < m_formatCtx->nb_streams; i++) { AVStream* & ffstream = m_formatCtx->streams[i]; try { std::shared_ptr<Stream> stream; switch (ffstream->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: stream = std::make_shared<VideoStream>(m_formatCtx, ffstream, *this, timer, videoDelegate); if (m_duration == sf::Time::Zero) { extractDurationFromStream(ffstream); } sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " video stream"); break; case AVMEDIA_TYPE_AUDIO: stream = std::make_shared<AudioStream>(m_formatCtx, ffstream, *this, timer); if (m_duration == sf::Time::Zero) { extractDurationFromStream(ffstream); } sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " audio stream"); break; case AVMEDIA_TYPE_SUBTITLE: stream = std::make_shared<SubtitleStream>(m_formatCtx, ffstream, *this, timer, subtitleDelegate); sfeLogDebug("Loaded " + avcodec_get_name(ffstream->codec->codec_id) + " subtitle stream"); break; default: m_ignoredStreams[ffstream->index] = Stream::AVStreamDescription(ffstream); sfeLogDebug(m_ignoredStreams[ffstream->index] + " ignored"); break; } // Don't create an entry in the map unless everything went well and stream did not get ignored if (stream) m_streams[ffstream->index] = stream; } catch (std::runtime_error& e) { std::string streamDesc = Stream::AVStreamDescription(ffstream); sfeLogError("error while loading " + streamDesc + ": " + e.what()); CHECK(m_streams.find(ffstream->index) == m_streams.end(), "Internal inconcistency error: stream whose loading failed should not be stored"); } } if (m_duration == sf::Time::Zero) { sfeLogWarning("The media duration could not be retreived"); } m_timer->addObserver(*this, DemuxerTimerPriority); }