// Blocks until decoded sample is produced by the deoder. nsresult GonkVideoDecoderManager::Output(int64_t aStreamOffset, nsAutoPtr<MediaData>& aOutData) { aOutData = nullptr; status_t err; if (mDecoder == nullptr) { ALOG("Decoder is not inited"); return NS_ERROR_UNEXPECTED; } err = mDecoder->Output(&mVideoBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US); switch (err) { case OK: { VideoData* data = nullptr; nsresult rv = CreateVideoData(aStreamOffset, &data); if (rv == NS_ERROR_NOT_AVAILABLE) { // Decoder outputs a empty video buffer, try again return NS_ERROR_NOT_AVAILABLE; } else if (rv != NS_OK || data == nullptr) { ALOG("Failed to create VideoData"); return NS_ERROR_UNEXPECTED; } aOutData = data; return NS_OK; } case android::INFO_FORMAT_CHANGED: { // If the format changed, update our cached info. ALOG("Decoder format changed"); if (!SetVideoFormat()) { return NS_ERROR_UNEXPECTED; } return Output(aStreamOffset, aOutData); } case android::INFO_OUTPUT_BUFFERS_CHANGED: { if (mDecoder->UpdateOutputBuffers()) { return Output(aStreamOffset, aOutData); } return NS_ERROR_FAILURE; } case -EAGAIN: { return NS_ERROR_NOT_AVAILABLE; } case android::ERROR_END_OF_STREAM: { ALOG("Got the EOS frame!"); VideoData* data = nullptr; nsresult rv = CreateVideoData(aStreamOffset, &data); if (rv == NS_ERROR_NOT_AVAILABLE) { // For EOS, no need to do any thing. return NS_ERROR_ABORT; } if (rv != NS_OK || data == nullptr) { ALOG("Failed to create video data"); return NS_ERROR_UNEXPECTED; } aOutData = data; return NS_ERROR_ABORT; } case -ETIMEDOUT: { ALOG("Timeout. can try again next time"); return NS_ERROR_UNEXPECTED; } default: { ALOG("Decoder failed, err=%d", err); return NS_ERROR_UNEXPECTED; } } return NS_OK; }
bool AVIDump::CreateFile() { m_totalBytes = 0; m_frameCount = 0; char movie_file_name[255]; sprintf(movie_file_name, "%sframedump%d.avi", File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), m_fileCount); // Create path File::CreateFullPath(movie_file_name); // Ask to delete file if (File::Exists(movie_file_name)) { if (AskYesNoT("Delete the existing file '%s'?", movie_file_name)) File::Delete(movie_file_name); } AVIFileInit(); NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name); // TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG HRESULT hr = AVIFileOpenA(&m_file, movie_file_name, OF_WRITE | OF_CREATE, NULL); if (FAILED(hr)) { if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format."); if (hr == AVIERR_MEMORY) NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory."); if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file."); if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file."); if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered"); Stop(); return false; } SetBitmapFormat(); NOTICE_LOG(VIDEO, "Setting video format..."); if (!SetVideoFormat()) { NOTICE_LOG(VIDEO, "Setting video format failed"); Stop(); return false; } if (!m_fileCount) { if (!SetCompressionOptions()) { NOTICE_LOG(VIDEO, "SetCompressionOptions failed"); Stop(); return false; } } if (FAILED(AVIMakeCompressedStream(&m_streamCompressed, m_stream, &m_options, NULL))) { NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed"); Stop(); return false; } if (FAILED(AVIStreamSetFormat(m_streamCompressed, 0, &m_bitmap, m_bitmap.biSize))) { NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed"); Stop(); return false; } return true; }
bool cDvbDevice::SetPlayMode(ePlayMode PlayMode) { if (PlayMode != pmExtern_THIS_SHOULD_BE_AVOIDED && fd_video < 0 && fd_audio < 0) { // reopen the devices fd_video = DvbOpen(DEV_DVB_VIDEO, CardIndex(), O_RDWR | O_NONBLOCK); fd_audio = DvbOpen(DEV_DVB_AUDIO, CardIndex(), O_RDWR | O_NONBLOCK); SetVideoFormat(Setup.VideoFormat); } switch (PlayMode) { case pmNone: // special handling to return from PCM replay: CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); CHECK(ioctl(fd_video, VIDEO_PLAY)); CHECK(ioctl(fd_video, VIDEO_STOP, true)); CHECK(ioctl(fd_audio, AUDIO_STOP, true)); CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); break; case pmAudioVideo: case pmAudioOnlyBlack: if (playMode == pmNone) TurnOffLiveMode(true); CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo)); CHECK(ioctl(fd_audio, AUDIO_PLAY)); CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); CHECK(ioctl(fd_video, VIDEO_PLAY)); break; case pmAudioOnly: CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_audio, AUDIO_STOP, true)); CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); CHECK(ioctl(fd_audio, AUDIO_PLAY)); CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); break; case pmVideoOnly: CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true)); CHECK(ioctl(fd_video, VIDEO_STOP, true)); CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX)); CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false)); CHECK(ioctl(fd_audio, AUDIO_PLAY)); CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER)); CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY)); CHECK(ioctl(fd_video, VIDEO_PLAY)); break; case pmExtern_THIS_SHOULD_BE_AVOIDED: close(fd_video); close(fd_audio); fd_video = fd_audio = -1; break; } playMode = PlayMode; return true; }
cDvbDevice::cDvbDevice(int n) { dvbTuner = NULL; frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN spuDecoder = NULL; digitalAudio = false; playMode = pmNone; // Devices that are present on all card types: int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK); // Devices that are only present on cards with decoders: fd_osd = DvbOpen(DEV_DVB_OSD, n, O_RDWR); fd_video = DvbOpen(DEV_DVB_VIDEO, n, O_RDWR | O_NONBLOCK); fd_audio = DvbOpen(DEV_DVB_AUDIO, n, O_RDWR | O_NONBLOCK); fd_stc = DvbOpen(DEV_DVB_DEMUX, n, O_RDWR); // The DVR device (will be opened and closed as needed): fd_dvr = -1; // The offset of the /dev/video devices: if (devVideoOffset < 0) { // the first one checks this FILE *f = NULL; char buffer[PATH_MAX]; for (int ofs = 0; ofs < 100; ofs++) { snprintf(buffer, sizeof(buffer), "/proc/video/dev/video%d", ofs); if ((f = fopen(buffer, "r")) != NULL) { if (fgets(buffer, sizeof(buffer), f)) { if (strstr(buffer, "DVB Board")) { // found the _first_ DVB card devVideoOffset = ofs; dsyslog("video device offset is %d", devVideoOffset); break; } } else break; fclose(f); } else break; } if (devVideoOffset < 0) devVideoOffset = 0; if (f) fclose(f); } devVideoIndex = (devVideoOffset >= 0 && HasDecoder()) ? devVideoOffset++ : -1; // Video format: SetVideoFormat(Setup.VideoFormat); // We only check the devices that must be present - the others will be checked before accessing them://XXX if (fd_frontend >= 0) { dvb_frontend_info feinfo; if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) { frontendType = feinfo.type; ciHandler = cCiHandler::CreateCiHandler(*cDvbName(DEV_DVB_CA, n)); dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType, ciHandler); } else LOG_ERROR; } else esyslog("ERROR: can't open DVB device %d", n); StartSectionHandler(); }
bool AVIDump::CreateFile() { s_total_bytes = 0; s_frame_count = 0; std::string movie_file_name = ""; //Dragonbane: Movie Logic bool lastSide = false; movie_file_name = GetCurrDumpFile(s_file_count, false); if (Movie::cmp_isRunning) { if (Movie::cmp_leftFinished || Movie::cmp_rightFinished) lastSide = true; } if (!lastSide) //Dragonbane: Stay silent if last side is recorded { // Create path File::CreateFullPath(movie_file_name); // Ask to delete file if (File::Exists(movie_file_name)) { if (SConfig::GetInstance().m_DumpFramesSilent || AskYesNoT("Delete the existing file '%s'?", movie_file_name.c_str())) { File::Delete(movie_file_name); } } } AVIFileInit(); NOTICE_LOG(VIDEO, "Opening AVI file (%s) for dumping", movie_file_name.c_str()); // TODO: Make this work with AVIFileOpenW without it throwing REGDB_E_CLASSNOTREG HRESULT hr = AVIFileOpenA(&s_file, movie_file_name.c_str(), OF_WRITE | OF_CREATE, nullptr); if (FAILED(hr)) { if (hr == AVIERR_BADFORMAT) NOTICE_LOG(VIDEO, "The file couldn't be read, indicating a corrupt file or an unrecognized format."); if (hr == AVIERR_MEMORY) NOTICE_LOG(VIDEO, "The file could not be opened because of insufficient memory."); if (hr == AVIERR_FILEREAD) NOTICE_LOG(VIDEO, "A disk error occurred while reading the file."); if (hr == AVIERR_FILEOPEN) NOTICE_LOG(VIDEO, "A disk error occurred while opening the file."); if (hr == REGDB_E_CLASSNOTREG) NOTICE_LOG(VIDEO, "AVI class not registered"); Stop(); return false; } SetBitmapFormat(); NOTICE_LOG(VIDEO, "Setting video format..."); if (!SetVideoFormat()) { NOTICE_LOG(VIDEO, "Setting video format failed"); Stop(); return false; } if (!s_file_count && !lastSide) //Dragonbane: Stay silent and re-use settings if last side is recorded { if (!SetCompressionOptions()) { NOTICE_LOG(VIDEO, "SetCompressionOptions failed"); Stop(); return false; } } if (FAILED(AVIMakeCompressedStream(&s_stream_compressed, s_stream, &s_options, nullptr))) { NOTICE_LOG(VIDEO, "AVIMakeCompressedStream failed"); Stop(); return false; } if (FAILED(AVIStreamSetFormat(s_stream_compressed, 0, &s_bitmap, s_bitmap.biSize))) { NOTICE_LOG(VIDEO, "AVIStreamSetFormat failed"); Stop(); return false; } return true; }
bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aSeekTimeUs, BufferCallback *aBufferCallback) { MOZ_ASSERT(aSeekTimeUs >= -1); if (!mVideoSource.get()) return false; ReleaseVideoBuffer(); status_t err; if (aSeekTimeUs != -1) { ReadOptions options; options.setSeekTo(aSeekTimeUs); err = mVideoSource->read(&mVideoBuffer, &options); } else { err = mVideoSource->read(&mVideoBuffer); } aFrame->mSize = 0; if (err == OK && mVideoBuffer->range_length() > 0) { int64_t timeUs; int32_t keyFrame; if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs) ) { LOG("no frame time"); return false; } if (timeUs < 0) { LOG("frame time %lld must be nonnegative", timeUs); return false; } if (!mVideoBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) { keyFrame = 0; } char *data = reinterpret_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset(); size_t length = mVideoBuffer->range_length(); if (!ToVideoFrame(aFrame, timeUs, data, length, keyFrame, aBufferCallback)) { return false; } } else if (err == INFO_FORMAT_CHANGED) { // If the format changed, update our cached info. LOG("mVideoSource INFO_FORMAT_CHANGED"); if (!SetVideoFormat()) return false; else return ReadVideo(aFrame, aSeekTimeUs, aBufferCallback); } else if (err == ERROR_END_OF_STREAM) { LOG("mVideoSource END_OF_STREAM"); } else if (err != OK) { LOG("mVideoSource ERROR %#x", err); } return err == OK; }
bool OmxDecoder::Init() { #if defined(MOZ_WIDGET_ANDROID) // OMXClient::connect() always returns OK and aborts fatally if // it can't connect. We may need to implement the connect functionality // ourselves if this proves to be an issue. if (!sClientInstance.IsValid()) { LOG("OMXClient failed to connect"); return false; } #endif //register sniffers, if they are not registered in this process. DataSource::RegisterDefaultSniffers(); sp<DataSource> dataSource = DataSource::CreateFromURI(static_cast<char*>(mDecoder->mResource)); if (!dataSource.get() || dataSource->initCheck()) { return false; } sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); if (extractor == nullptr) { return false; } ssize_t audioTrackIndex = -1; ssize_t videoTrackIndex = -1; const char *audioMime = nullptr; const char *videoMime = nullptr; for (size_t i = 0; i < extractor->countTracks(); ++i) { sp<MetaData> meta = extractor->getTrackMetaData(i); const char *mime; if (!meta->findCString(kKeyMIMEType, &mime)) { continue; } if (videoTrackIndex == -1 && !strncasecmp(mime, "video/", 6)) { videoTrackIndex = i; videoMime = mime; } else if (audioTrackIndex == -1 && !strncasecmp(mime, "audio/", 6)) { audioTrackIndex = i; audioMime = mime; } } if (videoTrackIndex == -1 && audioTrackIndex == -1) { return false; } int64_t totalDurationUs = 0; #ifdef MOZ_WIDGET_GONK sp<IOMX> omx = GetOMX(); #else sp<IOMX> omx = sClientInstance.get()->interface(); #endif sp<MediaSource> videoTrack; sp<MediaSource> videoSource; if (videoTrackIndex != -1 && (videoTrack = extractor->getTrack(videoTrackIndex)) != nullptr) { videoSource = CreateVideoSource(mPluginHost, omx, videoTrack); if (videoSource == nullptr) { LOG("OMXCodec failed to initialize video decoder for \"%s\"", videoMime); return false; } status_t status = videoSource->start(); if (status != OK) { LOG("videoSource->start() failed with status %#x", status); return false; } int64_t durationUs; if (videoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { if (durationUs < 0) LOG("video duration %lld should be nonnegative", durationUs); if (durationUs > totalDurationUs) totalDurationUs = durationUs; } } sp<MediaSource> audioTrack; sp<MediaSource> audioSource; if (audioTrackIndex != -1 && (audioTrack = extractor->getTrack(audioTrackIndex)) != nullptr) { if (!strcasecmp(audioMime, "audio/raw")) { audioSource = audioTrack; } else { audioSource = OMXCodec::Create(omx, audioTrack->getFormat(), false, // decoder audioTrack); } if (audioSource == nullptr) { LOG("OMXCodec failed to initialize audio decoder for \"%s\"", audioMime); return false; } status_t status = audioSource->start(); if (status != OK) { LOG("audioSource->start() failed with status %#x", status); return false; } int64_t durationUs; if (audioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { if (durationUs < 0) LOG("audio duration %lld should be nonnegative", durationUs); if (durationUs > totalDurationUs) totalDurationUs = durationUs; } } // set decoder state mVideoTrack = videoTrack; mVideoSource = videoSource; mAudioTrack = audioTrack; mAudioSource = audioSource; mDurationUs = totalDurationUs; if (mVideoSource.get() && !SetVideoFormat()) return false; // To reliably get the channel and sample rate data we need to read from the // audio source until we get a INFO_FORMAT_CHANGE status if (mAudioSource.get()) { if (mAudioSource->read(&mAudioBuffer) != INFO_FORMAT_CHANGED) { sp<MetaData> meta = mAudioSource->getFormat(); if (!meta->findInt32(kKeyChannelCount, &mAudioChannels) || !meta->findInt32(kKeySampleRate, &mAudioSampleRate)) { return false; } mAudioMetadataRead = true; if (mAudioChannels < 0) { LOG("audio channel count %d must be nonnegative", mAudioChannels); return false; } if (mAudioSampleRate < 0) { LOG("audio sample rate %d must be nonnegative", mAudioSampleRate); return false; } } else if (!SetAudioFormat()) { return false; } } return true; }