diff --git a/singe/videoPlayer.c b/singe/videoPlayer.c index f9a3a176b..c36921827 100644 --- a/singe/videoPlayer.c +++ b/singe/videoPlayer.c @@ -235,17 +235,17 @@ int32_t _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bo // Find audio track v->audioTrack = FFMS_GetFirstTrackOfType(aIndex, FFMS_TYPE_AUDIO, &v->errInfo); - if (v->audioTrack < 0) utilDie("%s", v->errInfo.Buffer); - v->audioSource = FFMS_CreateAudioSource(aFilename, v->audioTrack, aIndex, FFMS_DELAY_FIRST_VIDEO_TRACK, &v->errInfo); - if (v->audioSource == NULL) utilDie("%s", v->errInfo.Buffer); - - // Get audio properties - v->audioProps = FFMS_GetAudioProperties(v->audioSource); + if (v->audioTrack >= 0) { + v->audioSource = FFMS_CreateAudioSource(aFilename, v->audioTrack, aIndex, FFMS_DELAY_FIRST_VIDEO_TRACK, &v->errInfo); + if (v->audioSource == NULL) utilDie("%s", v->errInfo.Buffer); + // Get audio properties + v->audioProps = FFMS_GetAudioProperties(v->audioSource); + } // Indicies are now part of audioSource & videoSource, so release these FFMS_DestroyIndex(vIndex); vIndex = NULL; - if (aFilename != vFilename) { + if ((aFilename != vFilename) && (aIndex)) { FFMS_DestroyIndex(aIndex); } aIndex = NULL; @@ -258,56 +258,59 @@ int32_t _loadVideoAndAudio(char *vFilename, char *aFilename, char *indexPath, bo SDL_RenderSetLogicalSize(renderer, v->propFrame->EncodedWidth, v->propFrame->EncodedHeight); } - // Determine audio format - switch (v->audioProps->SampleFormat) { - case FFMS_FMT_U8: - v->audioFormat = AUDIO_U8; - v->audioSampleBytes = 1; - break; - case FFMS_FMT_S16: - v->audioFormat = AUDIO_S16SYS; - v->audioSampleBytes = 2; - break; - case FFMS_FMT_S32: - v->audioFormat = AUDIO_S32SYS; - v->audioSampleBytes = 4; - break; - case FFMS_FMT_FLT: - v->audioFormat = AUDIO_F32SYS; - v->audioSampleBytes = 4; - break; - default: - utilDie("Unknown audio sample format."); - break; + // Do we have audio? + if (v->audioSource) { + // Determine audio format + switch (v->audioProps->SampleFormat) { + case FFMS_FMT_U8: + v->audioFormat = AUDIO_U8; + v->audioSampleBytes = 1; + break; + case FFMS_FMT_S16: + v->audioFormat = AUDIO_S16SYS; + v->audioSampleBytes = 2; + break; + case FFMS_FMT_S32: + v->audioFormat = AUDIO_S32SYS; + v->audioSampleBytes = 4; + break; + case FFMS_FMT_FLT: + v->audioFormat = AUDIO_F32SYS; + v->audioSampleBytes = 4; + break; + default: + utilDie("Unknown audio sample format."); + break; + } + if (v->audioProps->Channels > 2) utilDie("Only mono and stereo audio are supported."); + + // Create audio stream to convert audio to our desired format + v->audioStream = SDL_NewAudioStream(v->audioFormat, (Uint8)v->audioProps->Channels, v->audioProps->SampleRate, _mixFormat, _mixChannels, _mixRate); + if (!v->audioStream) utilDie("%s", SDL_GetError()); + + // Create a buffer to read audio into before conversion + v->mixSampleSize = SDL_AUDIO_BITSIZE(_mixFormat) / 8 * _mixChannels; + v->audioSampleSize = v->audioSampleBytes * v->audioProps->Channels; + v->audioBufferSize = v->audioSampleSize * AUDIO_SAMPLE_PREREAD; + v->audioBuffer = (byte *)malloc((size_t)v->audioBufferSize * sizeof(byte)); + if (!v->audioBuffer) utilDie("Unable to allocate %ld byte audio buffer.", (size_t)v->audioBufferSize * sizeof(byte)); + + // Create a block of silent audio to overlay with video stream audio + v->audioSilenceSize = (Uint32)(_mixRate * SDL_AUDIO_BITSIZE(_mixFormat) / 8 * AUDIO_SILENCE_SECONDS); + v->audioSilenceRaw = (byte *)calloc(1, (size_t)v->audioSilenceSize * sizeof(byte)); + if (!v->audioSilenceRaw) utilDie("Unable to allocate %ld silence buffer.", v->audioSilenceSize); + + // Load silent audio + v->silenceChunk = Mix_QuickLoad_RAW(v->audioSilenceRaw, v->audioSilenceSize); + if (!v->silenceChunk) utilDie("%s", Mix_GetError()); + + // Start silent audio playback & immediately pause it + v->audioSilenceChannel = Mix_PlayChannel(-1, v->silenceChunk, -1); + if (v->audioSilenceChannel < 0) utilDie("%s", Mix_GetError()); + + // Register effect to provide video stream audio on this channel + Mix_RegisterEffect(v->audioSilenceChannel, _dequeueVideoAudio, NULL, v); } - if (v->audioProps->Channels > 2) utilDie("Only mono and stereo audio are supported."); - - // Create audio stream to convert audio to our desired format - v->audioStream = SDL_NewAudioStream(v->audioFormat, (Uint8)v->audioProps->Channels, v->audioProps->SampleRate, _mixFormat, _mixChannels, _mixRate); - if (!v->audioStream) utilDie("%s", SDL_GetError()); - - // Create a buffer to read audio into before conversion - v->mixSampleSize = SDL_AUDIO_BITSIZE(_mixFormat) / 8 * _mixChannels; - v->audioSampleSize = v->audioSampleBytes * v->audioProps->Channels; - v->audioBufferSize = v->audioSampleSize * AUDIO_SAMPLE_PREREAD; - v->audioBuffer = (byte *)malloc((size_t)v->audioBufferSize * sizeof(byte)); - if (!v->audioBuffer) utilDie("Unable to allocate %ld byte audio buffer.", (size_t)v->audioBufferSize * sizeof(byte)); - - // Create a block of silent audio to overlay with video stream audio - v->audioSilenceSize = (Uint32)(_mixRate * SDL_AUDIO_BITSIZE(_mixFormat) / 8 * AUDIO_SILENCE_SECONDS); - v->audioSilenceRaw = (byte *)calloc(1, (size_t)v->audioSilenceSize * sizeof(byte)); - if (!v->audioSilenceRaw) utilDie("Unable to allocate %ld silence buffer.", v->audioSilenceSize); - - // Load silent audio - v->silenceChunk = Mix_QuickLoad_RAW(v->audioSilenceRaw, v->audioSilenceSize); - if (!v->silenceChunk) utilDie("%s", Mix_GetError()); - - // Start silent audio playback & immediately pause it - v->audioSilenceChannel = Mix_PlayChannel(-1, v->silenceChunk, -1); - if (v->audioSilenceChannel < 0) utilDie("%s", Mix_GetError()); - - // Register effect to provide video stream audio on this channel - Mix_RegisterEffect(v->audioSilenceChannel, _dequeueVideoAudio, NULL, v); // Default volume, in percent v->volumeLeft = 100; @@ -518,16 +521,17 @@ int32_t videoUnload(int32_t playerHandle) { HASH_FIND_INT(_videoPlayerHash, &playerHandle, v); if (!v) utilDie("No video player at index %d in videoStop.", playerHandle); - Mix_HaltChannel(v->audioSilenceChannel); - Mix_UnregisterEffect(v->audioSilenceChannel, _dequeueVideoAudio); - Mix_FreeChunk(v->silenceChunk); - free(v->audioSilenceRaw); - SDL_FreeAudioStream(v->audioStream); - free(v->audioBuffer); + if (v->audioSource) { + Mix_HaltChannel(v->audioSilenceChannel); + Mix_UnregisterEffect(v->audioSilenceChannel, _dequeueVideoAudio); + Mix_FreeChunk(v->silenceChunk); + free(v->audioSilenceRaw); + SDL_FreeAudioStream(v->audioStream); + free(v->audioBuffer); + FFMS_DestroyAudioSource(v->audioSource); + } - FFMS_DestroyAudioSource(v->audioSource); FFMS_DestroyVideoSource(v->videoSource); - SDL_DestroyTexture(v->videoTexture); #pragma GCC diagnostic push @@ -552,7 +556,11 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) { if (!v) utilDie("No video player at index %d in videoUpdate.", playerHandle); // Audio drift limit - threshold = (v->audioProps->SampleRate / 2); + if (v->audioSource) { + threshold = (v->audioProps->SampleRate / 2); + } else { + threshold = 99999; + } // Handle video frames (and time) if ((SDL_GetTicks() - v->lastTickTime >= v->frameDeltaTime) || (v->audioDelta > threshold) || v->resetTime) { @@ -564,22 +572,23 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) { } *texture = v->videoTexture; - result = v->frame; + result = v->frame; v->framesPlayed++; - // Did we trip the audio sync compensation? - if (v->audioDelta > threshold) { - // Adjust frame rate to try and match - if (v->audioDelta > 0) { - v->audioAdjustment += 0.000001; - } else { - v->audioAdjustment -= 0.000001; + if (v->audioSource) { + // Did we trip the audio sync compensation? + if (v->audioDelta > threshold) { + // Adjust frame rate to try and match + if (v->audioDelta > 0) { + v->audioAdjustment += 0.000001; + } else { + v->audioAdjustment -= 0.000001; + } } + // Used to determine if we should play two frames rapidly to catch up to audio + v->audioDelta = labs(v->audioPosition - (int64_t)((double)v->timestamp * 0.001 * (double)v->audioProps->SampleRate)); } - // Used to determine if we should play two frames rapidly to catch up to audio - v->audioDelta = labs(v->audioPosition - (int64_t)((double)v->timestamp * 0.001 * (double)v->audioProps->SampleRate)); - //utilSay("D %ld T %ld A %f", v->audioDelta, threshold, v->audioAdjustment); v->frameData = FFMS_GetFrame(v->videoSource, v->frame, &v->errInfo); @@ -598,31 +607,35 @@ int32_t videoUpdate(int32_t playerHandle, SDL_Texture **texture) { } if (v->resetTime) { - SDL_AudioStreamClear(v->audioStream); - v->lastTickTime = 0; + if (v->audioSource) { + SDL_AudioStreamClear(v->audioStream); + v->audioPosition = (int64_t)((double)v->timestamp * 0.001 * (double)v->audioProps->SampleRate); + v->audioDelta = 0; + } + v->lastTickTime = 0; v->frameDeltaTime = 0; - v->audioPosition = (int64_t)((double)v->timestamp * 0.001 * (double)v->audioProps->SampleRate); - v->resetTime = false; - v->audioDelta = 0; - v->framesPlayed = 0; + v->resetTime = false; + v->framesPlayed = 0; } } // Handle audio samples - if ((v->playing) && (SDL_AudioStreamAvailable(v->audioStream) < AUDIO_STREAM_LOW_WATERMARK) && (v->audioPosition < v->audioProps->NumSamples)) { - // Maximum samples we can read at a time - count = AUDIO_SAMPLE_PREREAD; - // Don't read past end of audio data - if (v->audioPosition + count >= v->audioProps->NumSamples) { - count = v->audioProps->NumSamples - v->audioPosition - 1; - } - // Are we reading anything? - if (count > 0) { - // Get audio from video stream - if (FFMS_GetAudio(v->audioSource, v->audioBuffer, v->audioPosition, count, &v->errInfo)) utilDie("%s", v->errInfo.Buffer); - // Feed it to the mixer stream - if (SDL_AudioStreamPut(v->audioStream, v->audioBuffer, (int32_t)(count * v->audioSampleSize)) < 0) utilDie("%s", SDL_GetError()); - v->audioPosition += count; + if (v->audioSource) { + if ((v->playing) && (SDL_AudioStreamAvailable(v->audioStream) < AUDIO_STREAM_LOW_WATERMARK) && (v->audioPosition < v->audioProps->NumSamples)) { + // Maximum samples we can read at a time + count = AUDIO_SAMPLE_PREREAD; + // Don't read past end of audio data + if (v->audioPosition + count >= v->audioProps->NumSamples) { + count = v->audioProps->NumSamples - v->audioPosition - 1; + } + // Are we reading anything? + if (count > 0) { + // Get audio from video stream + if (FFMS_GetAudio(v->audioSource, v->audioBuffer, v->audioPosition, count, &v->errInfo)) utilDie("%s", v->errInfo.Buffer); + // Feed it to the mixer stream + if (SDL_AudioStreamPut(v->audioStream, v->audioBuffer, (int32_t)(count * v->audioSampleSize)) < 0) utilDie("%s", SDL_GetError()); + v->audioPosition += count; + } } }