// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_ENCODE_ACCELERATOR_H_ #define CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_ENCODE_ACCELERATOR_H_ #include #include #include "base/memory/linked_ptr.h" #include "base/threading/thread.h" #include "content/common/content_export.h" #include "content/common/gpu/media/h264_dpb.h" #include "content/common/gpu/media/va_surface.h" #include "content/common/gpu/media/vaapi_wrapper.h" #include "media/filters/h264_bitstream_buffer.h" #include "media/video/video_encode_accelerator.h" namespace content { // A VideoEncodeAccelerator implementation that uses VA-API // (http://www.freedesktop.org/wiki/Software/vaapi) for HW-accelerated // video encode. class CONTENT_EXPORT VaapiVideoEncodeAccelerator : public media::VideoEncodeAccelerator { public: explicit VaapiVideoEncodeAccelerator(Display* x_display); virtual ~VaapiVideoEncodeAccelerator(); // media::VideoEncodeAccelerator implementation. virtual std::vector GetSupportedProfiles() OVERRIDE; virtual bool Initialize(media::VideoFrame::Format format, const gfx::Size& input_visible_size, media::VideoCodecProfile output_profile, uint32 initial_bitrate, Client* client) OVERRIDE; virtual void Encode(const scoped_refptr& frame, bool force_keyframe) OVERRIDE; virtual void UseOutputBitstreamBuffer( const media::BitstreamBuffer& buffer) OVERRIDE; virtual void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate) OVERRIDE; virtual void Destroy() OVERRIDE; private: // Reference picture list. typedef std::list > RefPicList; // Encode job for one frame. Created when an input frame is awaiting and // enough resources are available to proceed. Once the job is prepared and // submitted to the hardware, it awaits on the submitted_encode_jobs_ queue // for an output bitstream buffer to become available. Once one is ready, // the encoded bytes are downloaded to it and job resources are released // and become available for reuse. struct EncodeJob { // Input surface for video frame data. scoped_refptr input_surface; // Surface for a reconstructed picture, which is used for reference // for subsequent frames. scoped_refptr recon_surface; // Buffer that will contain output bitstream for this frame. VABufferID coded_buffer; // Reference surfaces required to encode this picture. We keep references // to them here, because we may discard some of them from ref_pic_list* // before the HW job is done. RefPicList reference_surfaces; // True if this job will produce a keyframe. Used to report // to BitstreamBufferReady(). bool keyframe; EncodeJob(); ~EncodeJob(); }; // Encoder state. enum State { kUninitialized, kEncoding, kError, }; // Holds input frames coming from the client ready to be encoded. struct InputFrameRef; // Holds output buffers coming from the client ready to be filled. struct BitstreamBufferRef; // Tasks for each of the VEA interface calls to be executed on the // encoder thread. void InitializeTask(); void EncodeTask(const scoped_refptr& frame, bool force_keyframe); void UseOutputBitstreamBufferTask(scoped_ptr buffer_ref); void RequestEncodingParametersChangeTask(uint32 bitrate, uint32 framerate); void DestroyTask(); // Prepare and schedule an encode job if we have an input to encode // and enough resources to proceed. void EncodeFrameTask(); // Fill current_sps_/current_pps_ with current values. void UpdateSPS(); void UpdatePPS(); void UpdateRates(uint32 bitrate, uint32 framerate); // Generate packed SPS and PPS in packed_sps_/packed_pps_, using // values in current_sps_/current_pps_. void GeneratePackedSPS(); void GeneratePackedPPS(); // Check if we have sufficient resources for a new encode job, claim them and // fill current_encode_job_ with them. // Return false if we cannot start a new job yet, true otherwise. bool PrepareNextJob(); // Begin a new frame, making it a keyframe if |force_keyframe| is true, // updating current_pic_. void BeginFrame(bool force_keyframe); // End current frame, updating reference picture lists and storing current // job in the jobs awaiting completion on submitted_encode_jobs_. void EndFrame(); // Submit parameters for the current frame to the hardware. bool SubmitFrameParameters(); // Submit keyframe headers to the hardware if the current frame is a keyframe. bool SubmitHeadersIfNeeded(); // Upload image data from |frame| to the input surface for current job. bool UploadFrame(const scoped_refptr& frame); // Execute encode in hardware. This does not block and will return before // the job is finished. bool ExecuteEncode(); // Callback that returns a no longer used VASurfaceID to // available_va_surface_ids_ for reuse. void RecycleVASurfaceID(VASurfaceID va_surface_id); // Tries to return a bitstream buffer if both a submitted job awaits to // be completed and we have bitstream buffers from the client available // to download the encoded data to. void TryToReturnBitstreamBuffer(); // Puts the encoder into en error state and notifies client about the error. void NotifyError(Error error); // Sets the encoder state on the correct thread. void SetState(State state); // VaapiWrapper is the owner of all HW resources (surfaces and buffers) // and will free them on destruction. scoped_ptr vaapi_wrapper_; // Input profile and sizes. media::VideoCodecProfile profile_; gfx::Size visible_size_; gfx::Size coded_size_; // Macroblock-aligned. // Width/height in macroblocks. unsigned int mb_width_; unsigned int mb_height_; // Maximum size of the reference list 0. unsigned int max_ref_idx_l0_size_; // Initial QP. unsigned int qp_; // IDR frame period. unsigned int idr_period_; // I frame period. unsigned int i_period_; // IP period, i.e. how often do we need to have either an I or a P frame in // the stream. Period of 1 means we can have no B frames. unsigned int ip_period_; // Size in bytes required for input bitstream buffers. size_t output_buffer_byte_size_; Display* x_display_; // All of the members below must be accessed on the encoder_thread_, // while it is running. // Encoder state. Encode tasks will only run in kEncoding state. State state_; // frame_num to be used for the next frame. unsigned int frame_num_; // frame_num of the previous IDR. unsigned int last_idr_frame_num_; // Current bitrate in bps. unsigned int bitrate_; // Current fps. unsigned int framerate_; // CPB size in bits, i.e. bitrate in kbps * window size in ms/1000. unsigned int cpb_size_; // True if the parameters have changed and we need to submit a keyframe // with updated parameters. bool encoding_parameters_changed_; // Job currently being prepared for encode. scoped_ptr current_encode_job_; // Current SPS, PPS and their packed versions. Packed versions are their NALUs // in AnnexB format *without* emulation prevention three-byte sequences // (those will be added by the driver). media::H264SPS current_sps_; media::H264BitstreamBuffer packed_sps_; media::H264PPS current_pps_; media::H264BitstreamBuffer packed_pps_; // Picture currently being prepared for encode. H264Picture current_pic_; // VA surfaces available for reuse. std::vector available_va_surface_ids_; // VA buffers for coded frames. std::vector available_va_buffer_ids_; // Currently active reference surfaces. RefPicList ref_pic_list0_; // Callback via which finished VA surfaces are returned to us. VASurface::ReleaseCB va_surface_release_cb_; // VideoFrames passed from the client, waiting to be encoded. std::queue > encoder_input_queue_; // BitstreamBuffers mapped, ready to be filled. std::queue > available_bitstream_buffers_; // Jobs submitted for encode, awaiting bitstream buffers to become available. std::queue > submitted_encode_jobs_; // Encoder thread. All tasks are executed on it. base::Thread encoder_thread_; scoped_refptr encoder_thread_proxy_; const scoped_refptr child_message_loop_proxy_; // To expose client callbacks from VideoEncodeAccelerator. // NOTE: all calls to these objects *MUST* be executed on // child_message_loop_proxy_. scoped_ptr > client_ptr_factory_; base::WeakPtr client_; // WeakPtr to post from the encoder thread back to the ChildThread, as it may // outlive this. Posting from the ChildThread using base::Unretained(this) // to the encoder thread is safe, because |this| always outlives the encoder // thread (it's a member of this class). base::WeakPtr weak_this_; base::WeakPtrFactory weak_this_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(VaapiVideoEncodeAccelerator); }; } // namespace content #endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_VIDEO_ENCODE_ACCELERATOR_H_