1 // Copyright (c) 2018 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 #if defined (MFX_ENABLE_H264_VIDEO_DECODE)
23 
24 #include <algorithm>
25 
26 #include "umc_h264_segment_decoder_dxva.h"
27 #include "umc_h264_task_supplier.h"
28 #include "mfx_trace.h"
29 #include "mfxstructures.h"
30 
31 #include "vm_time.h"
32 
33 namespace UMC
34 {
H264_DXVA_SegmentDecoderCommon(TaskSupplier * pTaskSupplier)35 H264_DXVA_SegmentDecoderCommon::H264_DXVA_SegmentDecoderCommon(TaskSupplier * pTaskSupplier)
36     : H264SegmentDecoderBase(pTaskSupplier->GetTaskBroker())
37     , m_va(0)
38     , m_pTaskSupplier(pTaskSupplier)
39 {
40 }
41 
SetVideoAccelerator(VideoAccelerator * va)42 void H264_DXVA_SegmentDecoderCommon::SetVideoAccelerator(VideoAccelerator *va)
43 {
44     VM_ASSERT(va);
45     m_va = (VideoAccelerator*)va;
46 }
47 
H264_DXVA_SegmentDecoder(TaskSupplier * pTaskSupplier)48 H264_DXVA_SegmentDecoder::H264_DXVA_SegmentDecoder(TaskSupplier * pTaskSupplier)
49     : H264_DXVA_SegmentDecoderCommon(pTaskSupplier)
50 {
51 }
52 
~H264_DXVA_SegmentDecoder()53 H264_DXVA_SegmentDecoder::~H264_DXVA_SegmentDecoder()
54 {
55 }
56 
Init(int32_t iNumber)57 Status H264_DXVA_SegmentDecoder::Init(int32_t iNumber)
58 {
59     return H264SegmentDecoderBase::Init(iNumber);
60 }
61 
Reset()62 void H264_DXVA_SegmentDecoder::Reset()
63 {
64     if (m_Packer.get())
65         m_Packer->Reset();
66 }
67 
PackAllHeaders(H264DecoderFrame * pFrame,int32_t field)68 void H264_DXVA_SegmentDecoder::PackAllHeaders(H264DecoderFrame * pFrame, int32_t field)
69 {
70     if (!m_Packer.get())
71     {
72         m_Packer.reset(Packer::CreatePacker(m_va, m_pTaskSupplier));
73         if (!m_Packer.get())
74             throw h264_exception(UMC_ERR_FAILED);
75     }
76 
77     m_Packer->BeginFrame(pFrame, field);
78     m_Packer->PackAU(pFrame, field);
79     m_Packer->EndFrame();
80 }
81 
ProcessSegment(void)82 Status H264_DXVA_SegmentDecoder::ProcessSegment(void)
83 {
84     try{
85         if (m_pTaskBroker->GetNextTask(0))
86         {
87         }
88         else
89         {
90             return UMC_ERR_NOT_ENOUGH_DATA;
91         }
92     }catch(h264_exception &ex){
93         return ex.GetStatus();
94     }
95     return UMC_OK;
96 }
97 
98 
TaskBrokerSingleThreadDXVA(TaskSupplier * pTaskSupplier)99 TaskBrokerSingleThreadDXVA::TaskBrokerSingleThreadDXVA(TaskSupplier * pTaskSupplier)
100     : TaskBroker(pTaskSupplier)
101     , m_lastCounter(0)
102     , m_useDXVAStatusReporting(true)
103 {
104     m_counterFrequency = vm_time_get_frequency();
105 }
106 
PrepareFrame(H264DecoderFrame * pFrame)107 bool TaskBrokerSingleThreadDXVA::PrepareFrame(H264DecoderFrame * pFrame)
108 {
109     if (!pFrame || pFrame->m_iResourceNumber < 0)
110     {
111         return true;
112     }
113 
114     bool isSliceGroups = pFrame->GetAU(0)->IsSliceGroups() || pFrame->GetAU(1)->IsSliceGroups();
115     if (isSliceGroups)
116         pFrame->m_iResourceNumber = 0;
117 
118     if (pFrame->prepared[0] && pFrame->prepared[1])
119         return true;
120 
121     if (!pFrame->prepared[0] &&
122         (pFrame->GetAU(0)->GetStatus() == H264DecoderFrameInfo::STATUS_FILLED || pFrame->GetAU(0)->GetStatus() == H264DecoderFrameInfo::STATUS_STARTED))
123     {
124         pFrame->prepared[0] = true;
125     }
126 
127     if (!pFrame->prepared[1] &&
128         (pFrame->GetAU(1)->GetStatus() == H264DecoderFrameInfo::STATUS_FILLED || pFrame->GetAU(1)->GetStatus() == H264DecoderFrameInfo::STATUS_STARTED))
129     {
130         pFrame->prepared[1] = true;
131     }
132 
133     return true;
134 }
135 
Reset()136 void TaskBrokerSingleThreadDXVA::Reset()
137 {
138     m_lastCounter = 0;
139     TaskBroker::Reset();
140     m_reports.clear();
141 }
142 
Start()143 void TaskBrokerSingleThreadDXVA::Start()
144 {
145     AutomaticUMCMutex guard(m_mGuard);
146 
147     TaskBroker::Start();
148     m_completedQueue.clear();
149 
150     H264_DXVA_SegmentDecoder * dxva_sd = static_cast<H264_DXVA_SegmentDecoder *>(m_pTaskSupplier->m_pSegmentDecoder[0]);
151 
152     if (dxva_sd && dxva_sd->GetPacker() && dxva_sd->GetPacker()->GetVideoAccelerator())
153     {
154         m_useDXVAStatusReporting = dxva_sd->GetPacker()->GetVideoAccelerator()->IsUseStatusReport();
155     }
156 
157     if (m_useDXVAStatusReporting)
158         return;
159 
160     for (H264DecoderFrameInfo *pTemp = m_FirstAU; pTemp; pTemp = pTemp->GetNextAU())
161     {
162         pTemp->SetStatus(H264DecoderFrameInfo::STATUS_COMPLETED);
163     }
164 
165     for (H264DecoderFrameInfo *pTemp = m_FirstAU; pTemp; )
166     {
167         CompleteFrame(pTemp->m_pFrame);
168         pTemp = m_FirstAU;
169     }
170 
171     m_FirstAU = 0;
172 }
173 
174 enum
175 {
176     NUMBER_OF_STATUS = 512,
177 };
178 
179 
SetCompletedAndErrorStatus(uint8_t uiStatus,H264DecoderFrameInfo * au)180 void TaskBrokerSingleThreadDXVA::SetCompletedAndErrorStatus(uint8_t uiStatus, H264DecoderFrameInfo * au)
181 {
182     switch (uiStatus)
183     {
184     case 1:
185         au->m_pFrame->SetErrorFlagged(ERROR_FRAME_MINOR);
186         break;
187     case 2:
188         au->m_pFrame->SetErrorFlagged(ERROR_FRAME_MAJOR);
189         break;
190     case 3:
191         au->m_pFrame->SetErrorFlagged(ERROR_FRAME_MAJOR);
192         break;
193     case 4:
194         au->m_pFrame->SetErrorFlagged(ERROR_FRAME_MAJOR);
195         break;
196     }
197 
198     au->SetStatus(H264DecoderFrameInfo::STATUS_COMPLETED);
199     CompleteFrame(au->m_pFrame);
200 }
201 
202 
CheckCachedFeedbackAndComplete(H264DecoderFrameInfo * au)203 bool TaskBrokerSingleThreadDXVA::CheckCachedFeedbackAndComplete(H264DecoderFrameInfo * au)
204 {
205     for (uint32_t i = 0; i < m_reports.size(); i++)
206     {
207         if ((m_reports[i].m_index == (uint32_t)au->m_pFrame->m_index) && (au->IsBottom() == (m_reports[i].m_field != 0)))
208         {
209             SetCompletedAndErrorStatus(m_reports[i].m_status, au);
210             m_reports.erase(m_reports.begin() + i);
211             return true;
212         }
213     }
214     return false;
215 }
216 
GetNextTaskInternal(H264Task *)217 bool TaskBrokerSingleThreadDXVA::GetNextTaskInternal(H264Task *)
218 {
219     AutomaticUMCMutex guard(m_mGuard);
220 
221     if (!m_useDXVAStatusReporting)
222         return false;
223 
224     H264_DXVA_SegmentDecoder * dxva_sd = static_cast<H264_DXVA_SegmentDecoder *>(m_pTaskSupplier->m_pSegmentDecoder[0]);
225 
226     if (!dxva_sd->GetPacker())
227         return false;
228 
229     Status sts = UMC_OK;
230     for (H264DecoderFrameInfo * au = m_FirstAU; au; au = au->GetNextAU())
231     {
232         H264DecoderFrameInfo* prev = au->GetPrevAU();
233         //skip second field for sync.
234         bool skip = (prev && prev->m_pFrame == au->m_pFrame);
235 
236         uint16_t surfCorruption = 0;
237         if (!skip)
238         {
239             m_mGuard.Unlock();
240 
241             MFX_AUTO_LTRACE(MFX_TRACE_LEVEL_SCHED, "Dec vaSyncSurface");
242             sts = dxva_sd->GetPacker()->SyncTask(au->m_pFrame, &surfCorruption);
243 
244             m_mGuard.Lock();
245         }
246         //we should complete frame even we got an error
247         //this allows to return the error from [RunDecoding]
248         au->SetStatus(H264DecoderFrameInfo::STATUS_COMPLETED);
249         CompleteFrame(au->m_pFrame);
250 
251         if (sts < UMC_OK)
252         {
253             if (sts != UMC_ERR_GPU_HANG)
254                 sts = UMC_ERR_DEVICE_FAILED;
255 
256             au->m_pFrame->SetError(sts);
257         }
258         else
259             switch (surfCorruption)
260             {
261                 case MFX_CORRUPTION_MAJOR:
262                     au->m_pFrame->SetErrorFlagged(ERROR_FRAME_MAJOR);
263                     break;
264 
265                 case MFX_CORRUPTION_MINOR:
266                     au->m_pFrame->SetErrorFlagged(ERROR_FRAME_MINOR);
267                     break;
268             }
269 
270         if (sts != UMC_OK)
271             throw h264_exception(sts);
272 
273         if (!skip)
274         {
275             //query SO buffer with [SyncTask] only
276             sts = dxva_sd->GetPacker()->QueryStreamOut(au->m_pFrame);
277             if (sts != UMC_OK)
278                 throw h264_exception(sts);
279         }
280     }
281 
282     SwitchCurrentAU();
283 
284     return false;
285 }
286 
AwakeThreads()287 void TaskBrokerSingleThreadDXVA::AwakeThreads()
288 {
289 }
290 
291 } // namespace UMC
292 
293 #endif // MFX_ENABLE_H264_VIDEO_DECODE
294