blob: 3f860b63370677886ac2684eb4b05eb7250dd90a [file] [log] [blame]
// Copyright 2019 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string>
#include "starboard/common/log.h"
#include "starboard/common/scoped_ptr.h"
#include "starboard/configuration_constants.h"
#include "starboard/directory.h"
#include "starboard/event.h"
#include "starboard/player.h"
#include "starboard/shared/starboard/player/filter/audio_renderer_internal.h"
#include "starboard/shared/starboard/player/filter/player_components.h"
#include "starboard/shared/starboard/player/input_buffer_internal.h"
#include "starboard/shared/starboard/player/job_thread.h"
#include "starboard/shared/starboard/player/video_dmp_reader.h"
#include "starboard/system.h"
namespace {
using starboard::scoped_ptr;
using starboard::shared::starboard::player::InputBuffer;
using starboard::shared::starboard::player::InputBuffers;
using starboard::shared::starboard::player::JobThread;
using starboard::shared::starboard::player::filter::AudioRenderer;
using starboard::shared::starboard::player::filter::PlayerComponents;
using starboard::shared::starboard::player::video_dmp::VideoDmpReader;
#ifdef SB_MEDIA_PLAYER_THREAD_STACK_SIZE
const int kJobThreadStackSize = SB_MEDIA_PLAYER_THREAD_STACK_SIZE;
#else // SB_MEDIA_PLAYER_THREAD_STACK_SIZE
const int kJobThreadStackSize = 0;
#endif // SB_MEDIA_PLAYER_THREAD_STACK_SIZE
// TODO: Merge test file resolving function with the ones used in the player
// filter tests.
std::string GetTestInputDirectory() {
const size_t kPathSize = kSbFileMaxPath + 1;
std::vector<char> content_path(kPathSize);
SB_CHECK(SbSystemGetPath(kSbSystemPathContentDirectory, content_path.data(),
kPathSize));
std::string directory_path = std::string(content_path.data()) +
kSbFileSepChar + "test" + kSbFileSepChar +
"starboard" + kSbFileSepChar + "shared" +
kSbFileSepChar + "starboard" + kSbFileSepChar +
"player" + kSbFileSepChar + "testdata";
SB_CHECK(SbDirectoryCanOpen(directory_path.c_str()))
<< "Cannot open directory " << directory_path;
return directory_path;
}
std::string ResolveTestFileName(const char* filename) {
return GetTestInputDirectory() + kSbFileSepChar + filename;
}
scoped_ptr<VideoDmpReader> s_video_dmp_reader;
scoped_ptr<PlayerComponents> s_player_components;
int s_audio_sample_index;
scoped_ptr<JobThread> s_job_thread;
SbTime s_duration;
static void DeallocateSampleFunc(SbPlayer player,
void* context,
const void* sample_buffer) {}
starboard::scoped_refptr<InputBuffer> GetAudioInputBuffer(size_t index) {
auto player_sample_info =
s_video_dmp_reader->GetPlayerSampleInfo(kSbMediaTypeAudio, index);
return new InputBuffer(DeallocateSampleFunc, NULL, NULL, player_sample_info);
}
void OnTimer() {
if (!s_player_components->GetAudioRenderer()->CanAcceptMoreData()) {
s_job_thread->job_queue()->Schedule(std::bind(OnTimer), kSbTimeMillisecond);
return;
}
if (s_audio_sample_index == s_video_dmp_reader->number_of_audio_buffers()) {
SB_LOG(INFO) << "EOS written, duration " << s_duration << " microseconds.";
s_player_components->GetAudioRenderer()->WriteEndOfStream();
return;
} else {
InputBuffers input_buffers;
auto input_buffer = GetAudioInputBuffer(s_audio_sample_index);
s_duration = input_buffer->timestamp();
input_buffers.push_back(std::move(input_buffer));
s_player_components->GetAudioRenderer()->WriteSamples(input_buffers);
++s_audio_sample_index;
}
s_job_thread->job_queue()->Schedule(std::bind(OnTimer));
}
void ErrorCB(SbPlayerError error, const std::string& error_message) {
SB_NOTREACHED() << "ErrorCB is called with error " << error << ", "
<< error_message;
}
void PrerolledCB() {
SB_LOG(INFO) << "Playback started.";
s_player_components->GetMediaTimeProvider()->Play();
}
void EndedCB() {
SB_LOG(INFO) << "Playback finished.";
s_player_components.reset();
s_video_dmp_reader.reset();
SbSystemRequestStop(0);
}
void Start(const char* filename) {
SB_LOG(INFO) << "Loading " << filename;
s_video_dmp_reader.reset(
new VideoDmpReader(ResolveTestFileName(filename).c_str()));
scoped_ptr<PlayerComponents::Factory> factory =
PlayerComponents::Factory::Create();
PlayerComponents::Factory::CreationParameters creation_parameters(
s_video_dmp_reader->audio_codec(),
s_video_dmp_reader->audio_sample_info());
std::string error_message;
s_player_components =
factory->CreateComponents(creation_parameters, &error_message);
SB_DCHECK(s_player_components);
SB_DCHECK(s_player_components->GetAudioRenderer());
using std::placeholders::_1;
using std::placeholders::_2;
s_player_components->GetAudioRenderer()->Initialize(
std::bind(ErrorCB, _1, _2), std::bind(PrerolledCB), std::bind(EndedCB));
s_player_components->GetMediaTimeProvider()->SetPlaybackRate(1.0);
s_player_components->GetAudioRenderer()->SetVolume(1.0);
s_player_components->GetMediaTimeProvider()->Seek(0);
s_job_thread->job_queue()->Schedule(std::bind(OnTimer));
}
} // namespace
void SbEventHandle(const SbEvent* event) {
switch (event->type) {
case kSbEventTypeStart: {
SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
SB_DCHECK(data);
if (data->argument_count < 2) {
SB_LOG(INFO) << "Usage: audio_dmp_player <dmp file name>";
SB_LOG(INFO)
<< "e.g. audio_dmp_player beneath_the_canopy_aac_stereo.dmp";
SB_LOG(INFO)
<< " audio_dmp_player beneath_the_canopy_opus_stereo.dmp";
SbSystemRequestStop(0);
return;
}
s_job_thread.reset(new JobThread("audio", kJobThreadStackSize));
s_job_thread->job_queue()->Schedule(
std::bind(Start, data->argument_values[1]));
break;
}
case kSbEventTypeStop: {
s_job_thread.reset();
break;
}
default:
break;
}
}