diff options
Diffstat (limited to 'content')
3 files changed, 93 insertions, 13 deletions
diff --git a/content/common/gpu/media/omx_video_decode_accelerator.cc b/content/common/gpu/media/omx_video_decode_accelerator.cc index 27903c9..3c52456 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator.cc +++ b/content/common/gpu/media/omx_video_decode_accelerator.cc @@ -5,6 +5,7 @@ #include "content/common/gpu/media/omx_video_decode_accelerator.h" #include "base/debug/trace_event.h" +#include "base/logging.h" #include "base/stl_util.h" #include "base/string_util.h" #include "content/common/gpu/gpu_channel.h" @@ -45,6 +46,38 @@ static bool AreOMXFunctionPointersInitialized() { omx_free_handle && omx_deinit); } +// Maps the media::H264Profile members to the OMX_VIDEO_AVCPROFILETYPE members. +static OMX_U32 MapH264ProfileToOMXAVCProfile(uint32 profile) { + switch (profile) { + case media::H264PROFILE_NONE: + return OMX_VIDEO_AVCProfileMax; + case media::H264PROFILE_BASELINE: + return OMX_VIDEO_AVCProfileBaseline; + case media::H264PROFILE_MAIN: + return OMX_VIDEO_AVCProfileMain; + case media::H264PROFILE_EXTENDED: + return OMX_VIDEO_AVCProfileExtended; + case media::H264PROFILE_HIGH: + return OMX_VIDEO_AVCProfileHigh; + case media::H264PROFILE_HIGH10PROFILE: + return OMX_VIDEO_AVCProfileHigh10; + case media::H264PROFILE_HIGH422PROFILE: + return OMX_VIDEO_AVCProfileHigh422; + case media::H264PROFILE_HIGH444PREDICTIVEPROFILE: + return OMX_VIDEO_AVCProfileHigh444; + // Below enums don't have equivalent enum in Openmax. + case media::H264PROFILE_SCALABLEBASELINE: + case media::H264PROFILE_SCALABLEHIGH: + case media::H264PROFILE_STEREOHIGH: + case media::H264PROFILE_MULTIVIEWHIGH: + // Nvidia OMX video decoder requires the same resources (as that of the + // High profile) in every profile higher to the Main profile. + return OMX_VIDEO_AVCProfileHigh444; + } + NOTREACHED(); + return OMX_VIDEO_AVCProfileMax; +} + // Helper macros for dealing with failure. If |result| evaluates false, emit // |log| to ERROR, register |error| with the decoder, and return |ret_val| // (which may be omitted for functions that return void). @@ -76,7 +109,9 @@ OmxVideoDecodeAccelerator::OmxVideoDecodeAccelerator( input_buffers_at_component_(0), output_port_(0), output_buffers_at_component_(0), - client_(client) { + client_(client), + profile_(OMX_VIDEO_AVCProfileMax), + component_name_is_nvidia_h264ext_(false) { RETURN_ON_FAILURE(AreOMXFunctionPointersInitialized(), "Failed to load openmax library", PLATFORM_FAILURE,); RETURN_ON_OMX_FAILURE(omx_init(), "Failed to init OpenMAX core", @@ -126,6 +161,9 @@ bool OmxVideoDecodeAccelerator::VerifyConfigs( v == media::H264PROFILE_HIGH)) || (n == media::VIDEOATTRIBUTEKEY_VIDEOCOLORFORMAT && v == media::VIDEOCOLORFORMAT_RGBA)) { + if (n == media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_H264_PROFILE) { + profile_ = v; + } continue; } return false; @@ -189,6 +227,10 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { PLATFORM_FAILURE, false); client_state_ = OMX_StateLoaded; + component_name_is_nvidia_h264ext_ = !strcmp( + reinterpret_cast<char *>(component.get()), + "OMX.Nvidia.h264ext.decode"); + // Get the port information. This will obtain information about the number of // ports and index of the first port. OMX_PORT_PARAM_TYPE port_param; @@ -271,7 +313,6 @@ bool OmxVideoDecodeAccelerator::CreateComponent() { buffer->nOutputPortIndex = output_port_; CHECK(fake_output_buffers_.insert(buffer).second); } - return true; } @@ -473,6 +514,27 @@ void OmxVideoDecodeAccelerator::BeginTransitionToState( void OmxVideoDecodeAccelerator::OnReachedIdleInInitializing() { DCHECK_EQ(client_state_, OMX_StateLoaded); client_state_ = OMX_StateIdle; + // Query the resources with the component. + if (component_name_is_nvidia_h264ext_) { + OMX_INDEXTYPE extension_index; + OMX_ERRORTYPE result = OMX_GetExtensionIndex( + component_handle_, + const_cast<char*>("OMX.Nvidia.index.config.checkresources"), + &extension_index); + RETURN_ON_OMX_FAILURE(result, + "Failed to get the extension", + PLATFORM_FAILURE,); + OMX_VIDEO_PARAM_PROFILELEVELTYPE video_profile_level; + InitParam(*this, &video_profile_level); + video_profile_level.eProfile = MapH264ProfileToOMXAVCProfile(profile_); + RETURN_ON_FAILURE(video_profile_level.eProfile != OMX_VIDEO_AVCProfileMax, + "Unexpected profile", INVALID_ARGUMENT,); + result = OMX_SetConfig(component_handle_, extension_index, + &video_profile_level); + RETURN_ON_OMX_FAILURE(result, + "Resource Allocation failed", + PLATFORM_FAILURE,); + } BeginTransitionToState(OMX_StateExecuting); } diff --git a/content/common/gpu/media/omx_video_decode_accelerator.h b/content/common/gpu/media/omx_video_decode_accelerator.h index 357aca0..b744068 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator.h +++ b/content/common/gpu/media/omx_video_decode_accelerator.h @@ -184,6 +184,11 @@ class OmxVideoDecodeAccelerator : public media::VideoDecodeAccelerator { // NOTE: all calls to this object *MUST* be executed in message_loop_. Client* client_; + // These two members are only used during Initialization. + // OMX_VIDEO_AVCProfile requested during Initialization. + uint32 profile_; + bool component_name_is_nvidia_h264ext_; + // Method to handle events void EventHandlerCompleteTask(OMX_EVENTTYPE event, OMX_U32 data1, diff --git a/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc b/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc index dde60b1..49498e5 100644 --- a/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc +++ b/content/common/gpu/media/omx_video_decode_accelerator_unittest.cc @@ -58,8 +58,9 @@ namespace { // - |minFPSwithRender| and |minFPSnoRender| are minimum frames/second speeds // expected to be achieved with and without rendering to the screen, resp. // (the latter tests just decode speed). +// - |profile| is the media::H264Profile set during Initialization. // An empty value for a numeric field means "ignore". -const char* test_video_data = "test-25fps.h264:320:240:250:258:50:175"; +const char* test_video_data = "test-25fps.h264:320:240:250:258:50:175:1"; // Parse |data| into its constituent parts and set the various output fields // accordingly. CHECK-fails on unexpected or missing required data. @@ -70,14 +71,16 @@ void ParseTestVideoData(std::string data, int* num_frames, int* num_NALUs, int* min_fps_render, - int* min_fps_no_render) { + int* min_fps_no_render, + int* profile) { std::vector<std::string> elements; base::SplitString(data, ':', &elements); CHECK_GE(elements.size(), 1U) << data; - CHECK_LE(elements.size(), 7U) << data; + CHECK_LE(elements.size(), 8U) << data; *file_name = elements[0]; *width = *height = *num_frames = *num_NALUs = -1; *min_fps_render = *min_fps_no_render = -1; + *profile = -1; if (!elements[1].empty()) CHECK(base::StringToInt(elements[1], width)); if (!elements[2].empty()) @@ -90,6 +93,8 @@ void ParseTestVideoData(std::string data, CHECK(base::StringToInt(elements[5], min_fps_render)); if (!elements[6].empty()) CHECK(base::StringToInt(elements[6], min_fps_no_render)); + if (!elements[7].empty()) + CHECK(base::StringToInt(elements[7], profile)); } @@ -464,7 +469,8 @@ class EglRenderingVDAClient : public VideoDecodeAccelerator::Client { int num_NALUs_per_decode, int num_in_flight_decodes, int reset_after_frame_num, - int delete_decoder_state); + int delete_decoder_state, + int profile); virtual ~EglRenderingVDAClient(); void CreateDecoder(); @@ -526,6 +532,7 @@ class EglRenderingVDAClient : public VideoDecodeAccelerator::Client { PictureBufferById picture_buffers_by_id_; base::TimeTicks initialize_done_ticks_; base::TimeTicks last_frame_delivered_ticks_; + int profile_; }; EglRenderingVDAClient::EglRenderingVDAClient( @@ -536,7 +543,8 @@ EglRenderingVDAClient::EglRenderingVDAClient( int num_NALUs_per_decode, int num_in_flight_decodes, int reset_after_frame_num, - int delete_decoder_state) + int delete_decoder_state, + int profile) : rendering_helper_(rendering_helper), rendering_window_id_(rendering_window_id), encoded_data_(encoded_data), num_NALUs_per_decode_(num_NALUs_per_decode), @@ -545,7 +553,8 @@ EglRenderingVDAClient::EglRenderingVDAClient( note_(note), reset_after_frame_num_(reset_after_frame_num), delete_decoder_state_(delete_decoder_state), state_(CS_CREATED), - num_decoded_frames_(0), num_done_bitstream_buffers_(0) { + num_decoded_frames_(0), num_done_bitstream_buffers_(0), + profile_(profile) { CHECK_GT(num_NALUs_per_decode, 0); CHECK_GT(num_in_flight_decodes, 0); } @@ -572,7 +581,11 @@ void EglRenderingVDAClient::CreateDecoder() { media::VIDEOATTRIBUTEKEY_VIDEOCOLORFORMAT, media::VIDEOCOLORFORMAT_RGBA, }; std::vector<int32> config( - config_array, config_array + arraysize(config_array)); + config_array, config_array + arraysize(config_array)); + if (profile_ != -1) { + config.push_back(media::VIDEOATTRIBUTEKEY_BITSTREAMFORMAT_H264_PROFILE); + config.push_back(profile_); + } CHECK(decoder_->Initialize(config)); } @@ -798,7 +811,7 @@ static void AssertWaitForStateOrDeleted(ClientStateNotification* note, // We assert the exact number of concurrent decoders we expect to succeed and // that one more than that fails initialization. -enum { kMaxSupportedNumConcurrentDecoders = 5 }; +enum { kMaxSupportedNumConcurrentDecoders = 3 }; // Test the most straightforward case possible: data is decoded from a single // chunk and rendered to the screen. @@ -817,10 +830,10 @@ TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { std::string test_video_file; int frame_width, frame_height; - int num_frames, num_NALUs, min_fps_render, min_fps_no_render; + int num_frames, num_NALUs, min_fps_render, min_fps_no_render, profile; ParseTestVideoData(test_video_data, &test_video_file, &frame_width, &frame_height, &num_frames, &num_NALUs, - &min_fps_render, &min_fps_no_render); + &min_fps_render, &min_fps_no_render, &profile); min_fps_render /= num_concurrent_decoders; min_fps_no_render /= num_concurrent_decoders; @@ -862,7 +875,7 @@ TEST_P(OmxVideoDecodeAcceleratorTest, TestSimpleDecode) { &rendering_helper, index, note, data_str, num_NALUs_per_decode, num_in_flight_decodes, - reset_after_frame_num, delete_decoder_state); + reset_after_frame_num, delete_decoder_state, profile); clients[index] = client; rendering_thread.message_loop()->PostTask( |