123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- /* ---------------------------------------------------------------------------
- ** This software is in the public domain, furnished "as is", without technical
- ** support, and with no warranty, express or implied, as to its usefulness for
- ** any purpose.
- **
- ** VideoDecoder.h
- **
- ** -------------------------------------------------------------------------*/
- #pragma once
- #include <string.h>
- #include <vector>
- #include "api/video/i420_buffer.h"
- #include "modules/video_coding/include/video_error_codes.h"
- #include "modules/video_coding/h264_sprop_parameter_sets.h"
- class VideoDecoder : public webrtc::DecodedImageCallback {
- private:
- class Frame
- {
- public:
- Frame(): m_timestamp_ms(0) {}
- Frame(const rtc::scoped_refptr<webrtc::EncodedImageBuffer> & content, uint64_t timestamp_ms, webrtc::VideoFrameType frameType) : m_content(content), m_timestamp_ms(timestamp_ms), m_frameType(frameType) {}
-
- rtc::scoped_refptr<webrtc::EncodedImageBuffer> m_content;
- uint64_t m_timestamp_ms;
- webrtc::VideoFrameType m_frameType;
- };
- public:
- VideoDecoder(rtc::VideoBroadcaster& broadcaster, std::unique_ptr<webrtc::VideoDecoderFactory>& videoDecoderFactory, bool wait) :
- m_broadcaster(broadcaster),
- m_factory(videoDecoderFactory),
- m_stop(false),
- m_wait(wait),
-
- m_previmagets(0),
- m_prevts(0) {
- }
- virtual ~VideoDecoder() {
- }
- void DecoderThread()
- {
- while (!m_stop) {
- std::unique_lock<std::mutex> mlock(m_queuemutex);
- while (m_queue.empty())
- {
- m_queuecond.wait(mlock);
- }
- Frame frame = m_queue.front();
- m_queue.pop();
- mlock.unlock();
-
- if (frame.m_content.get() != NULL) {
- RTC_LOG(LS_VERBOSE) << "VideoDecoder::DecoderThread size:" << frame.m_content->size() << " ts:" << frame.m_timestamp_ms;
- ssize_t size = frame.m_content->size();
-
- if (size) {
- webrtc::EncodedImage input_image;
- input_image.SetEncodedData(frame.m_content);
- input_image._frameType = frame.m_frameType;
- input_image.ntp_time_ms_ = frame.m_timestamp_ms;
- input_image.SetTimestamp(frame.m_timestamp_ms); // store time in ms that overflow the 32bits
- int res = m_decoder->Decode(input_image, false, frame.m_timestamp_ms);
- if (res != WEBRTC_VIDEO_CODEC_OK) {
- RTC_LOG(LS_ERROR) << "VideoDecoder::DecoderThread failure:" << res;
- }
- }
- }
- }
- }
- void Start()
- {
- RTC_LOG(LS_INFO) << "VideoDecoder::start";
- m_stop = false;
- m_decoderthread = std::thread(&VideoDecoder::DecoderThread, this);
- }
- void Stop()
- {
- RTC_LOG(LS_INFO) << "VideoDecoder::stop";
- m_stop = true;
- Frame frame;
- {
- std::unique_lock<std::mutex> lock(m_queuemutex);
- m_queue.push(frame);
- }
- m_queuecond.notify_all();
- m_decoderthread.join();
- }
- std::vector< std::vector<uint8_t> > getInitFrames(const std::string & codec, const char* sdp) {
- std::vector< std::vector<uint8_t> > frames;
- if (codec == "H264") {
- const char* pattern="sprop-parameter-sets=";
- const char* sprop=strstr(sdp, pattern);
- if (sprop)
- {
- std::string sdpstr(sprop+strlen(pattern));
- size_t pos = sdpstr.find_first_of(" ;\r\n");
- if (pos != std::string::npos)
- {
- sdpstr.erase(pos);
- }
- webrtc::H264SpropParameterSets sprops;
- if (sprops.DecodeSprop(sdpstr))
- {
- std::vector<uint8_t> sps;
- sps.insert(sps.end(), H26X_marker, H26X_marker+sizeof(H26X_marker));
- sps.insert(sps.end(), sprops.sps_nalu().begin(), sprops.sps_nalu().end());
- frames.push_back(sps);
- std::vector<uint8_t> pps;
- pps.insert(pps.end(), H26X_marker, H26X_marker+sizeof(H26X_marker));
- pps.insert(pps.end(), sprops.pps_nalu().begin(), sprops.pps_nalu().end());
- frames.push_back(pps);
- }
- else
- {
- RTC_LOG(WARNING) << "Cannot decode SPS:" << sprop;
- }
- }
- }
- return frames;
- }
- void createDecoder(const std::string & codec, int width = 0, int height = 0) {
- webrtc::VideoCodec codec_settings;
- codec_settings.width=width;
- codec_settings.height=height;
- if (codec == "H264") {
- m_decoder=m_factory->CreateVideoDecoder(webrtc::SdpVideoFormat(cricket::kH264CodecName));
- codec_settings.codecType = webrtc::VideoCodecType::kVideoCodecH264;
-
- }
- if (m_decoder.get() != NULL) {
- m_decoder->InitDecode(&codec_settings,2);
- m_decoder->RegisterDecodeCompleteCallback(this);
- }
- }
- void destroyDecoder() {
- m_decoder.reset(NULL);
- }
- bool hasDecoder() {
- return (m_decoder.get() != NULL);
- }
- void PostFrame(const rtc::scoped_refptr<webrtc::EncodedImageBuffer>& content, uint64_t ts, webrtc::VideoFrameType frameType) {
- Frame frame(content, ts, frameType);
- {
- std::unique_lock<std::mutex> lock(m_queuemutex);
- m_queue.push(frame);
- }
- m_queuecond.notify_all();
- }
- // overide webrtc::DecodedImageCallback
- virtual int32_t Decoded(webrtc::VideoFrame& decodedImage) override {
- int64_t ts = std::chrono::high_resolution_clock::now().time_since_epoch().count()/1000/1000;
- RTC_LOG(LS_VERBOSE) << "VideoDecoder::Decoded size:" << decodedImage.size()
- << " decode ts:" << decodedImage.ntp_time_ms()
- << " source ts:" << ts;
- // waiting
- if ( (m_wait) && (m_prevts != 0) ) {
- int64_t periodSource = decodedImage.timestamp() - m_previmagets;
- int64_t periodDecode = ts-m_prevts;
-
- RTC_LOG(LS_VERBOSE) << "VideoDecoder::Decoded interframe decode:" << periodDecode << " source:" << periodSource;
- int64_t delayms = periodSource-periodDecode;
- if ( (delayms > 0) && (delayms < 1000) ) {
- std::this_thread::sleep_for(std::chrono::milliseconds(delayms));
- }
- } else {
- std::this_thread::sleep_for(std::chrono::milliseconds(5));
- }
-
-
-
- m_broadcaster.OnFrame(decodedImage);
-
- m_previmagets = decodedImage.timestamp();
- m_prevts = std::chrono::high_resolution_clock::now().time_since_epoch().count()/1000/1000;
-
- return 1;
- }
- rtc::VideoBroadcaster& m_broadcaster;
- std::unique_ptr<webrtc::VideoDecoderFactory>& m_factory;
- std::unique_ptr<webrtc::VideoDecoder> m_decoder;
- std::queue<Frame> m_queue;
- std::mutex m_queuemutex;
- std::condition_variable m_queuecond;
- std::thread m_decoderthread;
- bool m_stop;
- bool m_wait;
- int64_t m_previmagets;
- int64_t m_prevts;
-
- };
|