| // Copyright (c) 2012 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. |
| // |
| // This file contains an implementation of a class that provides H264 decode |
| // support for use with VAAPI hardware video decode acceleration on Intel |
| // systems. |
| |
| #ifndef CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_ |
| #define CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_ |
| |
| #include <vector> |
| |
| #include "base/callback_forward.h" |
| #include "base/memory/linked_ptr.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "content/common/gpu/media/h264_dpb.h" |
| #include "content/common/gpu/media/vaapi_wrapper.h" |
| #include "media/base/limits.h" |
| #include "media/filters/h264_parser.h" |
| |
| namespace content { |
| |
| // An H264 decoder that utilizes VA-API. Provides features not supported by |
| // the VA-API userspace library (libva), including stream parsing, reference |
| // picture management and other operations not supported by the HW codec. |
| // |
| // Provides functionality to allow plugging VAAPI HW acceleration into the |
| // VDA framework. |
| // |
| // Clients of this class are expected to pass H264 Annex-B byte stream and |
| // will receive decoded surfaces via client-provided |OutputPicCB|. |
| // |
| // This class must be created, called and destroyed on a single thread, and |
| // does nothing internally on any other thread. |
| class CONTENT_EXPORT VaapiH264Decoder { |
| public: |
| // Callback invoked on the client when a surface is to be displayed. |
| // Arguments: input buffer id provided at the time of Decode() |
| // and VASurface to output. |
| typedef base::Callback< |
| void(int32, const scoped_refptr<VASurface>&)> OutputPicCB; |
| |
| enum VAVDAH264DecoderFailure { |
| FRAME_MBS_ONLY_FLAG_NOT_ONE = 0, |
| GAPS_IN_FRAME_NUM = 1, |
| MID_STREAM_RESOLUTION_CHANGE = 2, |
| INTERLACED_STREAM = 3, |
| VAAPI_ERROR = 4, |
| VAVDA_H264_DECODER_FAILURES_MAX, |
| }; |
| |
| // Callback to report errors for UMA purposes, not used to return errors |
| // to clients. |
| typedef base::Callback<void(VAVDAH264DecoderFailure error)> |
| ReportErrorToUmaCB; |
| |
| // Decode result codes. |
| enum DecResult { |
| kDecodeError, // Error while decoding. |
| // TODO posciak: unsupported streams are currently treated as error |
| // in decoding; in future it could perhaps be possible to fall back |
| // to software decoding instead. |
| // kStreamError, // Error in stream. |
| kAllocateNewSurfaces, // Need a new set of surfaces to be allocated. |
| kRanOutOfStreamData, // Need more stream data to proceed. |
| kRanOutOfSurfaces, // Waiting for the client to free up output surfaces. |
| }; |
| |
| // |vaapi_wrapper| should be initialized. |
| // |output_pic_cb| notifies the client a surface is to be displayed. |
| // |report_error_to_uma_cb| called on errors for UMA purposes, not used |
| // to report errors to clients. |
| VaapiH264Decoder(VaapiWrapper* vaapi_wrapper, |
| const OutputPicCB& output_pic_cb, |
| const ReportErrorToUmaCB& report_error_to_uma_cb); |
| |
| ~VaapiH264Decoder(); |
| |
| // Have the decoder flush its state and trigger output of all previously |
| // decoded surfaces via OutputPicCB. Return false on failure. |
| bool Flush() WARN_UNUSED_RESULT; |
| |
| // To be called during decoding. |
| // Stop (pause) decoding, discarding all remaining inputs and outputs, |
| // but do not flush decoder state, so that the playback can be resumed later, |
| // possibly from a different location. |
| void Reset(); |
| |
| // Set current stream data pointer to |ptr| and |size|. Output surfaces |
| // that are decoded from data in this stream chunk are to be returned along |
| // with the given |input_id|. |
| void SetStream(const uint8* ptr, size_t size, int32 input_id); |
| |
| // Try to decode more of the stream, returning decoded frames asynchronously |
| // via output_pic_cb_. Return when more stream is needed, when we run out |
| // of free surfaces, when we need a new set of them, or when an error occurs. |
| DecResult Decode() WARN_UNUSED_RESULT; |
| |
| // Return dimensions/required number of output surfaces that client should |
| // be ready to provide for the decoder to function properly. |
| // To be used after Decode() returns kNeedNewSurfaces. |
| gfx::Size GetPicSize() { return pic_size_; } |
| size_t GetRequiredNumOfPictures(); |
| |
| // To be used by the client to feed decoder with output surfaces. |
| void ReuseSurface(const scoped_refptr<VASurface>& va_surface); |
| |
| private: |
| // We need to keep at most kDPBMaxSize pictures in DPB for |
| // reference/to display later and an additional one for the one currently |
| // being decoded. We also ask for some additional ones since VDA needs |
| // to accumulate a few ready-to-output pictures before it actually starts |
| // displaying and giving them back. +2 instead of +1 because of subjective |
| // smoothness improvement during testing. |
| enum { |
| kPicsInPipeline = media::limits::kMaxVideoFrames + 2, |
| kMaxNumReqPictures = H264DPB::kDPBMaxSize + kPicsInPipeline, |
| }; |
| |
| // Internal state of the decoder. |
| enum State { |
| kNeedStreamMetadata, // After initialization, need an SPS. |
| kDecoding, // Ready to decode from any point. |
| kAfterReset, // After Reset(), need a resume point. |
| kError, // Error in decode, can't continue. |
| }; |
| |
| // Process H264 stream structures. |
| bool ProcessSPS(int sps_id, bool* need_new_buffers); |
| bool ProcessPPS(int pps_id); |
| bool ProcessSlice(media::H264SliceHeader* slice_hdr); |
| |
| // Initialize the current picture according to data in |slice_hdr|. |
| bool InitCurrPicture(media::H264SliceHeader* slice_hdr); |
| |
| // Calculate picture order counts for the new picture |
| // on initialization of a new frame (see spec). |
| bool CalculatePicOrderCounts(media::H264SliceHeader* slice_hdr); |
| |
| // Update PicNum values in pictures stored in DPB on creation of new |
| // frame (see spec). |
| void UpdatePicNums(); |
| |
| bool UpdateMaxNumReorderFrames(const media::H264SPS* sps); |
| |
| // Prepare reference picture lists (ref_pic_list[01]_). |
| bool PrepareRefPicLists(media::H264SliceHeader* slice_hdr); |
| |
| // Construct initial reference picture lists for use in decoding of |
| // P and B pictures (see 8.2.4 in spec). |
| void ConstructReferencePicListsP(media::H264SliceHeader* slice_hdr); |
| void ConstructReferencePicListsB(media::H264SliceHeader* slice_hdr); |
| |
| // Helper functions for reference list construction, per spec. |
| int PicNumF(H264Picture *pic); |
| int LongTermPicNumF(H264Picture *pic); |
| |
| // Perform the reference picture lists' modification (reordering), as |
| // specified in spec (8.2.4). |
| // |
| // |list| indicates list number and should be either 0 or 1. |
| bool ModifyReferencePicList(media::H264SliceHeader* slice_hdr, int list); |
| |
| // Perform reference picture memory management operations (marking/unmarking |
| // of reference pictures, long term picture management, discarding, etc.). |
| // See 8.2.5 in spec. |
| bool HandleMemoryManagementOps(); |
| void ReferencePictureMarking(); |
| |
| // Start processing a new frame. |
| bool StartNewFrame(media::H264SliceHeader* slice_hdr); |
| |
| // All data for a frame received, process it and decode. |
| bool FinishPrevFrameIfPresent(); |
| |
| // Called after decoding, performs all operations to be done after decoding, |
| // including DPB management, reference picture marking and memory management |
| // operations. |
| // This will also output a picture if one is ready for output. |
| bool FinishPicture(); |
| |
| // Clear DPB contents and remove all surfaces in DPB from *in_use_ list. |
| // Cleared pictures will be made available for decode, unless they are |
| // at client waiting to be displayed. |
| void ClearDPB(); |
| |
| // These queue up data for HW decoder to be committed on running HW decode. |
| bool SendPPS(); |
| bool SendIQMatrix(); |
| bool SendVASliceParam(media::H264SliceHeader* slice_hdr); |
| bool SendSliceData(const uint8* ptr, size_t size); |
| bool QueueSlice(media::H264SliceHeader* slice_hdr); |
| |
| // Helper methods for filling HW structures. |
| void FillVAPicture(VAPictureH264 *va_pic, H264Picture* pic); |
| int FillVARefFramesFromDPB(VAPictureH264 *va_pics, int num_pics); |
| |
| // Commits all pending data for HW decoder and starts HW decoder. |
| bool DecodePicture(); |
| |
| // Notifies client that a picture is ready for output. |
| bool OutputPic(H264Picture* pic); |
| |
| // Output all pictures in DPB that have not been outputted yet. |
| bool OutputAllRemainingPics(); |
| |
| // Represents a frame being decoded. Will always have a VASurface |
| // assigned to it, which will eventually contain decoded picture data. |
| class DecodeSurface; |
| |
| // Assign an available surface to the given PicOrderCnt |poc|, |
| // removing it from the available surfaces pool. Return true if a surface |
| // has been found, false otherwise. |
| bool AssignSurfaceToPoC(int32 input_id, int poc); |
| |
| // Indicate that a surface is no longer needed by decoder. |
| void UnassignSurfaceFromPoC(int poc); |
| |
| // Return DecodeSurface assigned to |poc|. |
| DecodeSurface* DecodeSurfaceByPoC(int poc); |
| |
| // Decoder state. |
| State state_; |
| |
| // Parser in use. |
| media::H264Parser parser_; |
| |
| // DPB in use. |
| H264DPB dpb_; |
| |
| // Picture currently being processed/decoded. |
| scoped_ptr<H264Picture> curr_pic_; |
| |
| // Reference picture lists, constructed for each picture before decoding. |
| // Those lists are not owners of the pointers (DPB is). |
| H264Picture::PtrVector ref_pic_list0_; |
| H264Picture::PtrVector ref_pic_list1_; |
| |
| // Global state values, needed in decoding. See spec. |
| int max_pic_order_cnt_lsb_; |
| int max_frame_num_; |
| int max_pic_num_; |
| int max_long_term_frame_idx_; |
| size_t max_num_reorder_frames_; |
| |
| int frame_num_; |
| int prev_frame_num_; |
| int prev_frame_num_offset_; |
| bool prev_has_memmgmnt5_; |
| |
| // Values related to previously decoded reference picture. |
| bool prev_ref_has_memmgmnt5_; |
| int prev_ref_top_field_order_cnt_; |
| int prev_ref_pic_order_cnt_msb_; |
| int prev_ref_pic_order_cnt_lsb_; |
| H264Picture::Field prev_ref_field_; |
| |
| // Currently active SPS and PPS. |
| int curr_sps_id_; |
| int curr_pps_id_; |
| |
| // Output picture size. |
| gfx::Size pic_size_; |
| |
| // Maps H.264 PicOrderCount to currently used DecodeSurfaces; |
| typedef std::map<int, linked_ptr<DecodeSurface> > DecSurfacesInUse; |
| DecSurfacesInUse decode_surfaces_in_use_; |
| |
| // Unused VA surfaces returned by client, ready to be reused. |
| std::vector<scoped_refptr<VASurface> > available_va_surfaces_; |
| |
| // The id of current input buffer, which will be associated with an |
| // output surface when a frame is successfully decoded. |
| int32 curr_input_id_; |
| |
| VaapiWrapper* vaapi_wrapper_; |
| |
| // Called by decoder when a surface should be outputted. |
| OutputPicCB output_pic_cb_; |
| |
| // Called to report decoding error to UMA, not used to indicate errors |
| // to clients. |
| ReportErrorToUmaCB report_error_to_uma_cb_; |
| |
| // PicOrderCount of the previously outputted frame. |
| int last_output_poc_; |
| |
| DISALLOW_COPY_AND_ASSIGN(VaapiH264Decoder); |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_COMMON_GPU_MEDIA_VAAPI_H264_DECODER_H_ |