1 // Copyright (c) 2020 Intel Corporation
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 #include "umc_defs.h"
22 
23 #if defined (MFX_ENABLE_MPEG2_VIDEO_DECODE)
24 
25 #include "umc_mpeg2_defs.h"
26 #include "umc_mpeg2_slice.h"
27 #include "umc_mpeg2_frame.h"
28 #include "umc_mpeg2_va_packer.h"
29 #include "mfx_session.h"
30 
31 namespace UMC_MPEG2_DECODER
32 {
CreatePacker(UMC::VideoAccelerator * va)33     Packer * Packer::CreatePacker(UMC::VideoAccelerator * va)
34     {
35         return new PackerVA(va);
36     }
37 
Packer(UMC::VideoAccelerator * va)38     Packer::Packer(UMC::VideoAccelerator * va)
39         : m_va(va)
40     {}
41 
~Packer()42     Packer::~Packer()
43     {}
44 
45 
46 /****************************************************************************************************/
47 // Linux VAAPI packer implementation
48 /****************************************************************************************************/
49 
PackerVA(UMC::VideoAccelerator * va)50     PackerVA::PackerVA(UMC::VideoAccelerator * va)
51         : Packer(va)
52     {}
53 
BeginFrame()54     void PackerVA::BeginFrame() {}
EndFrame()55     void PackerVA::EndFrame() {}
56 
57     // Pack picture
PackAU(MPEG2DecoderFrame const & frame,uint8_t fieldIndex)58     void PackerVA::PackAU(MPEG2DecoderFrame const& frame, uint8_t fieldIndex)
59     {
60         int sliceCount = frame.GetAU(fieldIndex)->GetSliceCount();
61 
62         if (!sliceCount)
63             return;
64 
65         const MPEG2DecoderFrameInfo & frameInfo = *frame.GetAU(fieldIndex);
66         PackPicParams(frame, fieldIndex);
67 
68         PackQmatrix(frameInfo);
69 
70         CreateSliceDataBuffer(frameInfo);
71         CreateSliceParamBuffer(frameInfo);
72 
73         uint32_t sliceNum = 0;
74         for (int32_t n = 0; n < sliceCount; n++)
75         {
76             PackSliceParams(*frame.GetAU(fieldIndex)->GetSlice(n), sliceNum);
77             sliceNum++;
78         }
79 
80         if(m_va->m_MaxContextPriority)
81             PackPriorityParams();
82 
83         auto s = m_va->Execute();
84         if(s != UMC::UMC_OK)
85             throw mpeg2_exception(s);
86     }
87 
PackPriorityParams()88     void PackerVA::PackPriorityParams()
89     {
90         mfxPriority priority = m_va->m_ContextPriority;
91         UMC::UMCVACompBuffer *GpuPriorityBuf;
92         VAContextParameterUpdateBuffer* GpuPriorityBuf_Mpeg2Decode = (VAContextParameterUpdateBuffer *)m_va->GetCompBuffer(VAContextParameterUpdateBufferType, &GpuPriorityBuf, sizeof(VAContextParameterUpdateBuffer));
93         if (!GpuPriorityBuf_Mpeg2Decode)
94             throw mpeg2_exception(UMC::UMC_ERR_FAILED);
95 
96         memset(GpuPriorityBuf_Mpeg2Decode, 0, sizeof(VAContextParameterUpdateBuffer));
97         GpuPriorityBuf_Mpeg2Decode->flags.bits.context_priority_update = 1;
98 
99         if(priority == MFX_PRIORITY_LOW)
100         {
101             GpuPriorityBuf_Mpeg2Decode->context_priority.bits.priority = 0;
102         }
103         else if (priority == MFX_PRIORITY_HIGH)
104         {
105             GpuPriorityBuf_Mpeg2Decode->context_priority.bits.priority = m_va->m_MaxContextPriority;
106         }
107         else
108         {
109             GpuPriorityBuf_Mpeg2Decode->context_priority.bits.priority = m_va->m_MaxContextPriority/2;
110         }
111 
112         GpuPriorityBuf->SetDataSize(sizeof(VAContextParameterUpdateBuffer));
113     }
114 
115 
116     // Pack picture parameters
PackPicParams(const MPEG2DecoderFrame & frame,uint8_t fieldIndex)117     void PackerVA::PackPicParams(const MPEG2DecoderFrame & frame, uint8_t fieldIndex)
118     {
119         const MPEG2DecoderFrameInfo & frameInfo = *frame.GetAU(fieldIndex);
120         const auto slice  = frameInfo.GetSlice(0);
121         const auto seq    = slice->GetSeqHeader();
122         const auto pic    = slice->GetPicHeader();
123         const auto picExt = slice->GetPicExtHeader();
124 
125         UMC::UMCVACompBuffer *picParamBuf;
126         auto picParam = (VAPictureParameterBufferMPEG2*)m_va->GetCompBuffer(VAPictureParameterBufferType, &picParamBuf, sizeof(VAPictureParameterBufferMPEG2)); // Allocate buffer
127         if (!picParam)
128             throw mpeg2_exception(UMC::UMC_ERR_FAILED);
129 
130         picParamBuf->SetDataSize(sizeof(VAPictureParameterBufferMPEG2));
131         memset(picParam, 0, sizeof(VAPictureParameterBufferMPEG2));
132 
133         picParam->horizontal_size = seq.horizontal_size_value;
134         picParam->vertical_size   = seq.vertical_size_value;
135 
136         const auto refPic0 = frameInfo.GetForwardRefPic();
137         const auto refPic1 = frameInfo.GetBackwardRefPic();
138 
139         if (MPEG2_P_PICTURE == pic.picture_coding_type && refPic0)
140         {
141             picParam->forward_reference_picture  = (VASurfaceID)m_va->GetSurfaceID(refPic0->GetMemID());
142             picParam->backward_reference_picture = VA_INVALID_SURFACE;
143         }
144         else if (MPEG2_B_PICTURE == pic.picture_coding_type && refPic0 && refPic1)
145         {
146             picParam->forward_reference_picture  = (VASurfaceID)m_va->GetSurfaceID(refPic0->GetMemID());
147             picParam->backward_reference_picture = (VASurfaceID)m_va->GetSurfaceID(refPic1->GetMemID());
148         }
149         else
150         {
151             picParam->forward_reference_picture  = VA_INVALID_SURFACE;
152             picParam->backward_reference_picture = VA_INVALID_SURFACE;
153         }
154 
155         picParam->picture_coding_type = pic.picture_coding_type;
156         for (uint8_t i = 0; i < 4; ++i)
157         {
158             picParam->f_code |= (picExt.f_code[i] << (12 - 4*i));
159         }
160 
161         picParam->picture_coding_extension.bits.intra_dc_precision         = picExt.intra_dc_precision;
162         picParam->picture_coding_extension.bits.picture_structure          = picExt.picture_structure;
163         picParam->picture_coding_extension.bits.top_field_first            = picExt.top_field_first;
164         picParam->picture_coding_extension.bits.frame_pred_frame_dct       = picExt.frame_pred_frame_dct;
165         picParam->picture_coding_extension.bits.concealment_motion_vectors = picExt.concealment_motion_vectors;
166         picParam->picture_coding_extension.bits.q_scale_type               = picExt.q_scale_type;
167         picParam->picture_coding_extension.bits.intra_vlc_format           = picExt.intra_vlc_format;
168         picParam->picture_coding_extension.bits.alternate_scan             = picExt.alternate_scan;
169         picParam->picture_coding_extension.bits.repeat_first_field         = picExt.repeat_first_field;
170         picParam->picture_coding_extension.bits.progressive_frame          = picExt.progressive_frame;
171         picParam->picture_coding_extension.bits.is_first_field             = !( (picExt.picture_structure != FRM_PICTURE) && (fieldIndex == 1) ) ;
172     }
173 
CreateSliceParamBuffer(const MPEG2DecoderFrameInfo & info)174     void PackerVA::CreateSliceParamBuffer(const MPEG2DecoderFrameInfo & info)
175     {
176         uint32_t count = info.GetSliceCount();
177 
178         UMC::UMCVACompBuffer *pSliceParamBuf;
179         size_t sizeOfStruct = m_va->IsLongSliceControl() ? sizeof(VASliceParameterBufferMPEG2) : sizeof(VASliceParameterBufferBase);
180         m_va->GetCompBuffer(VASliceParameterBufferType, &pSliceParamBuf, sizeOfStruct*(count)); // Allocate buffer
181         if (!pSliceParamBuf)
182             throw mpeg2_exception(UMC::UMC_ERR_FAILED);
183 
184         pSliceParamBuf->SetNumOfItem(count);
185     }
186 
187     // Calculate size of slice data and create buffer
CreateSliceDataBuffer(const MPEG2DecoderFrameInfo & info)188     void PackerVA::CreateSliceDataBuffer(const MPEG2DecoderFrameInfo & info)
189     {
190         uint32_t count = info.GetSliceCount();
191         uint32_t size = 0;
192 
193         for (uint32_t i = 0; i < count; ++i)
194         {
195             MPEG2Slice* slice = info.GetSlice(i);
196 
197             uint8_t *nalUnit; //ptr to first byte of start code
198             uint32_t nalUnitSize; // size of NAL unit in byte
199 
200             slice->GetBitStream().GetOrg(nalUnit, nalUnitSize);
201             size += nalUnitSize + sizeof(start_code_prefix);
202         }
203 
204         UMC::UMCVACompBuffer* compBuf;
205         m_va->GetCompBuffer(VASliceDataBufferType, &compBuf, size); // Allocate buffer
206         if (!compBuf)
207             throw mpeg2_exception(UMC::UMC_ERR_FAILED);
208 
209         compBuf->SetDataSize(0);
210     }
211 
212     // Pack slice parameters
PackSliceParams(const MPEG2Slice & slice,uint32_t sliceNum)213     void PackerVA::PackSliceParams(const MPEG2Slice & slice, uint32_t sliceNum)
214     {
215         const auto sliceHeader = slice.GetSliceHeader();
216         const auto pic         = slice.GetPicHeader();
217 
218         UMC::UMCVACompBuffer* compBuf;
219         auto sliceParams = (VASliceParameterBufferMPEG2*)m_va->GetCompBuffer(VASliceParameterBufferType, &compBuf);
220         if (!sliceParams)
221             throw mpeg2_exception(UMC::UMC_ERR_FAILED);
222 
223         if (m_va->IsLongSliceControl())
224         {
225             sliceParams += sliceNum;
226             memset(sliceParams, 0, sizeof(VASliceParameterBufferMPEG2));
227         }
228         else
229         {
230             sliceParams = (VASliceParameterBufferMPEG2*)((VASliceParameterBufferBase*)sliceParams + sliceNum);
231             memset(sliceParams, 0, sizeof(VASliceParameterBufferBase));
232         }
233 
234         uint8_t *  rawDataPtr = nullptr;
235         uint32_t  rawDataSize = 0;
236 
237         slice.GetBitStream().GetOrg(rawDataPtr, rawDataSize);
238 
239         sliceParams->slice_data_size = rawDataSize + prefix_size;
240         sliceParams->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
241 
242         auto sliceDataBuf = (uint8_t*)m_va->GetCompBuffer(VASliceDataBufferType, &compBuf);
243         if (!sliceDataBuf)
244             throw mpeg2_exception(UMC::UMC_ERR_FAILED);
245 
246         sliceParams->slice_data_offset = compBuf->GetDataSize();
247         sliceDataBuf += sliceParams->slice_data_offset;
248         std::copy(start_code_prefix, start_code_prefix + prefix_size, sliceDataBuf);
249         std::copy(rawDataPtr, rawDataPtr + rawDataSize, sliceDataBuf + prefix_size);
250         compBuf->SetDataSize(sliceParams->slice_data_offset + sliceParams->slice_data_size);
251 
252         if (!m_va->IsLongSliceControl())
253             return;
254 
255         sliceParams->macroblock_offset         = sliceHeader.mbOffset + prefix_size * 8;
256         sliceParams->slice_horizontal_position = sliceHeader.macroblockAddressIncrement;
257         sliceParams->slice_vertical_position   = sliceHeader.slice_vertical_position - 1;
258         sliceParams->quantiser_scale_code      = sliceHeader.quantiser_scale_code;
259         sliceParams->intra_slice_flag          = (pic.picture_coding_type == MPEG2_I_PICTURE);
260 
261         return;
262     }
263 
264     static const uint8_t default_intra_quantizer_matrix[64] =
265     {
266          8, 16, 16, 19, 16, 19, 22, 22,
267         22, 22, 22, 22, 26, 24, 26, 27,
268         27, 27, 26, 26, 26, 26, 27, 27,
269         27, 29, 29, 29, 34, 34, 34, 29,
270         29, 29, 27, 27, 29, 29, 32, 32,
271         34, 34, 37, 38, 37, 35, 35, 34,
272         35, 38, 38, 40, 40, 40, 48, 48,
273         46, 46, 56, 56, 58, 69, 69, 83
274     };
275 
276     static const uint8_t default_non_intra_quantizer_matrix[64] =
277     {
278         16, 16, 16, 16, 16, 16, 16, 16,
279         16, 16, 16, 16, 16, 16, 16, 16,
280         16, 16, 16, 16, 16, 16, 16, 16,
281         16, 16, 16, 16, 16, 16, 16, 16,
282         16, 16, 16, 16, 16, 16, 16, 16,
283         16, 16, 16, 16, 16, 16, 16, 16,
284         16, 16, 16, 16, 16, 16, 16, 16,
285         16, 16, 16, 16, 16, 16, 16, 16
286     };
287 
288     // Pack matrix parameters
PackQmatrix(const MPEG2DecoderFrameInfo & info)289     void PackerVA::PackQmatrix(const MPEG2DecoderFrameInfo & info)
290     {
291         UMC::UMCVACompBuffer *quantBuf;
292         auto qmatrix = (VAIQMatrixBufferMPEG2*)m_va->GetCompBuffer(VAIQMatrixBufferType, &quantBuf, sizeof(VAIQMatrixBufferMPEG2)); // Allocate buffer
293         if (!qmatrix)
294             throw mpeg2_exception(UMC::UMC_ERR_FAILED);
295 
296         quantBuf->SetDataSize(sizeof(VAIQMatrixBufferMPEG2));
297 
298         const auto slice    = info.GetSlice(0);
299         const auto seq      = slice->GetSeqHeader();
300         const auto customQM = slice->GetQMatrix();
301 
302         // intra_quantizer_matrix
303         qmatrix->load_intra_quantiser_matrix = 1;
304         const uint8_t * intra_quantizer_matrix = customQM && customQM->load_intra_quantiser_matrix ?
305                                                     customQM->intra_quantiser_matrix :
306                                                     (seq.load_intra_quantiser_matrix ? seq.intra_quantiser_matrix : default_intra_quantizer_matrix);
307         std::copy(intra_quantizer_matrix, intra_quantizer_matrix + 64, qmatrix->intra_quantiser_matrix);
308 
309         // chroma_intra_quantiser_matrix
310         qmatrix->load_chroma_intra_quantiser_matrix = 1;
311         const uint8_t * chroma_intra_quantiser_matrix = customQM && customQM->load_chroma_intra_quantiser_matrix ?
312                                                             customQM->chroma_intra_quantiser_matrix :
313                                                             (seq.load_intra_quantiser_matrix ? seq.intra_quantiser_matrix : default_intra_quantizer_matrix);
314         std::copy(chroma_intra_quantiser_matrix, chroma_intra_quantiser_matrix + 64, qmatrix->chroma_intra_quantiser_matrix);
315 
316         // non_intra_quantiser_matrix
317         qmatrix->load_non_intra_quantiser_matrix = 1;
318         const uint8_t * non_intra_quantiser_matrix = customQM && customQM->load_non_intra_quantiser_matrix ?
319                                                         customQM->non_intra_quantiser_matrix :
320                                                         (seq.load_non_intra_quantiser_matrix ? seq.non_intra_quantiser_matrix : default_non_intra_quantizer_matrix);
321         std::copy(non_intra_quantiser_matrix, non_intra_quantiser_matrix + 64, qmatrix->non_intra_quantiser_matrix);
322 
323         // chroma_non_intra_quantiser_matrix
324         qmatrix->load_chroma_non_intra_quantiser_matrix = 1;
325         const uint8_t * chroma_non_intra_quantiser_matrix = customQM && customQM->load_chroma_non_intra_quantiser_matrix ?
326                                                                 customQM->chroma_non_intra_quantiser_matrix :
327                                                                 (seq.load_non_intra_quantiser_matrix ? seq.non_intra_quantiser_matrix : default_non_intra_quantizer_matrix);
328         std::copy(chroma_non_intra_quantiser_matrix, chroma_non_intra_quantiser_matrix + 64, qmatrix->chroma_non_intra_quantiser_matrix);
329     }
330 }
331 
332 #endif // MFX_ENABLE_MPEG2_VIDEO_DECODE
333