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