| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 #include <limits> | 6 #include <limits> |
| 7 | 7 |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
| 10 #include "base/numerics/safe_conversions.h" |
| 10 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
| 11 #include "content/common/gpu/media/vaapi_h264_decoder.h" | 12 #include "content/common/gpu/media/vaapi_h264_decoder.h" |
| 12 | 13 |
| 13 namespace content { | 14 namespace content { |
| 14 | 15 |
| 15 // Decode surface, used for decoding and reference. input_id comes from client | 16 // Decode surface, used for decoding and reference. input_id comes from client |
| 16 // and is associated with the surface that was produced as the result | 17 // and is associated with the surface that was produced as the result |
| 17 // of decoding a bitstream buffer with that id. | 18 // of decoding a bitstream buffer with that id. |
| 18 class VaapiH264Decoder::DecodeSurface { | 19 class VaapiH264Decoder::DecodeSurface { |
| 19 public: | 20 public: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 } | 56 } |
| 56 | 57 |
| 57 VaapiH264Decoder::VaapiH264Decoder( | 58 VaapiH264Decoder::VaapiH264Decoder( |
| 58 VaapiWrapper* vaapi_wrapper, | 59 VaapiWrapper* vaapi_wrapper, |
| 59 const OutputPicCB& output_pic_cb, | 60 const OutputPicCB& output_pic_cb, |
| 60 const ReportErrorToUmaCB& report_error_to_uma_cb) | 61 const ReportErrorToUmaCB& report_error_to_uma_cb) |
| 61 : max_pic_order_cnt_lsb_(0), | 62 : max_pic_order_cnt_lsb_(0), |
| 62 max_frame_num_(0), | 63 max_frame_num_(0), |
| 63 max_pic_num_(0), | 64 max_pic_num_(0), |
| 64 max_long_term_frame_idx_(0), | 65 max_long_term_frame_idx_(0), |
| 66 max_num_reorder_frames_(0), |
| 65 curr_sps_id_(-1), | 67 curr_sps_id_(-1), |
| 66 curr_pps_id_(-1), | 68 curr_pps_id_(-1), |
| 67 vaapi_wrapper_(vaapi_wrapper), | 69 vaapi_wrapper_(vaapi_wrapper), |
| 68 output_pic_cb_(output_pic_cb), | 70 output_pic_cb_(output_pic_cb), |
| 69 report_error_to_uma_cb_(report_error_to_uma_cb) { | 71 report_error_to_uma_cb_(report_error_to_uma_cb) { |
| 70 Reset(); | 72 Reset(); |
| 71 state_ = kNeedStreamMetadata; | 73 state_ = kNeedStreamMetadata; |
| 72 } | 74 } |
| 73 | 75 |
| 74 VaapiH264Decoder::~VaapiH264Decoder() { | 76 VaapiH264Decoder::~VaapiH264Decoder() { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 98 int poc = it->second->poc(); | 100 int poc = it->second->poc(); |
| 99 // Must be incremented before UnassignSurfaceFromPoC as this call | 101 // Must be incremented before UnassignSurfaceFromPoC as this call |
| 100 // invalidates |it|. | 102 // invalidates |it|. |
| 101 ++it; | 103 ++it; |
| 102 UnassignSurfaceFromPoC(poc); | 104 UnassignSurfaceFromPoC(poc); |
| 103 } | 105 } |
| 104 DCHECK(decode_surfaces_in_use_.empty()); | 106 DCHECK(decode_surfaces_in_use_.empty()); |
| 105 | 107 |
| 106 dpb_.Clear(); | 108 dpb_.Clear(); |
| 107 parser_.Reset(); | 109 parser_.Reset(); |
| 108 last_output_poc_ = 0; | 110 last_output_poc_ = std::numeric_limits<int>::min(); |
| 109 | 111 |
| 110 // If we are in kDecoding, we can resume without processing an SPS. | 112 // If we are in kDecoding, we can resume without processing an SPS. |
| 111 if (state_ == kDecoding) | 113 if (state_ == kDecoding) |
| 112 state_ = kAfterReset; | 114 state_ = kAfterReset; |
| 113 } | 115 } |
| 114 | 116 |
| 115 void VaapiH264Decoder::ReuseSurface( | 117 void VaapiH264Decoder::ReuseSurface( |
| 116 const scoped_refptr<VASurface>& va_surface) { | 118 const scoped_refptr<VASurface>& va_surface) { |
| 117 available_va_surfaces_.push_back(va_surface); | 119 available_va_surfaces_.push_back(va_surface); |
| 118 } | 120 } |
| (...skipping 916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1035 | 1037 |
| 1036 return true; | 1038 return true; |
| 1037 } | 1039 } |
| 1038 | 1040 |
| 1039 void VaapiH264Decoder::ClearDPB() { | 1041 void VaapiH264Decoder::ClearDPB() { |
| 1040 // Clear DPB contents, marking the pictures as unused first. | 1042 // Clear DPB contents, marking the pictures as unused first. |
| 1041 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) | 1043 for (H264DPB::Pictures::iterator it = dpb_.begin(); it != dpb_.end(); ++it) |
| 1042 UnassignSurfaceFromPoC((*it)->pic_order_cnt); | 1044 UnassignSurfaceFromPoC((*it)->pic_order_cnt); |
| 1043 | 1045 |
| 1044 dpb_.Clear(); | 1046 dpb_.Clear(); |
| 1045 last_output_poc_ = 0; | 1047 last_output_poc_ = std::numeric_limits<int>::min(); |
| 1046 } | 1048 } |
| 1047 | 1049 |
| 1048 bool VaapiH264Decoder::OutputAllRemainingPics() { | 1050 bool VaapiH264Decoder::OutputAllRemainingPics() { |
| 1049 // Output all pictures that are waiting to be outputted. | 1051 // Output all pictures that are waiting to be outputted. |
| 1050 FinishPrevFrameIfPresent(); | 1052 FinishPrevFrameIfPresent(); |
| 1051 H264Picture::PtrVector to_output; | 1053 H264Picture::PtrVector to_output; |
| 1052 dpb_.GetNotOutputtedPicsAppending(to_output); | 1054 dpb_.GetNotOutputtedPicsAppending(to_output); |
| 1053 // Sort them by ascending POC to output in order. | 1055 // Sort them by ascending POC to output in order. |
| 1054 std::sort(to_output.begin(), to_output.end(), POCAscCompare()); | 1056 std::sort(to_output.begin(), to_output.end(), POCAscCompare()); |
| 1055 | 1057 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1081 | 1083 |
| 1082 // If the new frame is an IDR, output what's left to output and clear DPB | 1084 // If the new frame is an IDR, output what's left to output and clear DPB |
| 1083 if (slice_hdr->idr_pic_flag) { | 1085 if (slice_hdr->idr_pic_flag) { |
| 1084 // (unless we are explicitly instructed not to do so). | 1086 // (unless we are explicitly instructed not to do so). |
| 1085 if (!slice_hdr->no_output_of_prior_pics_flag) { | 1087 if (!slice_hdr->no_output_of_prior_pics_flag) { |
| 1086 // Output DPB contents. | 1088 // Output DPB contents. |
| 1087 if (!Flush()) | 1089 if (!Flush()) |
| 1088 return false; | 1090 return false; |
| 1089 } | 1091 } |
| 1090 dpb_.Clear(); | 1092 dpb_.Clear(); |
| 1091 last_output_poc_ = 0; | 1093 last_output_poc_ = std::numeric_limits<int>::min(); |
| 1092 } | 1094 } |
| 1093 | 1095 |
| 1094 // curr_pic_ should have either been added to DPB or discarded when finishing | 1096 // curr_pic_ should have either been added to DPB or discarded when finishing |
| 1095 // the last frame. DPB is responsible for releasing that memory once it's | 1097 // the last frame. DPB is responsible for releasing that memory once it's |
| 1096 // not needed anymore. | 1098 // not needed anymore. |
| 1097 DCHECK(!curr_pic_.get()); | 1099 DCHECK(!curr_pic_.get()); |
| 1098 curr_pic_.reset(new H264Picture); | 1100 curr_pic_.reset(new H264Picture); |
| 1099 CHECK(curr_pic_.get()); | 1101 CHECK(curr_pic_.get()); |
| 1100 | 1102 |
| 1101 if (!InitCurrPicture(slice_hdr)) | 1103 if (!InitCurrPicture(slice_hdr)) |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1322 // reference), or the memory will be released if we manage to output it here | 1324 // reference), or the memory will be released if we manage to output it here |
| 1323 // without having to store it for future reference. | 1325 // without having to store it for future reference. |
| 1324 scoped_ptr<H264Picture> pic(curr_pic_.release()); | 1326 scoped_ptr<H264Picture> pic(curr_pic_.release()); |
| 1325 | 1327 |
| 1326 // Get all pictures that haven't been outputted yet. | 1328 // Get all pictures that haven't been outputted yet. |
| 1327 H264Picture::PtrVector not_outputted; | 1329 H264Picture::PtrVector not_outputted; |
| 1328 // TODO(posciak): pass as pointer, not reference (violates coding style). | 1330 // TODO(posciak): pass as pointer, not reference (violates coding style). |
| 1329 dpb_.GetNotOutputtedPicsAppending(not_outputted); | 1331 dpb_.GetNotOutputtedPicsAppending(not_outputted); |
| 1330 // Include the one we've just decoded. | 1332 // Include the one we've just decoded. |
| 1331 not_outputted.push_back(pic.get()); | 1333 not_outputted.push_back(pic.get()); |
| 1334 |
| 1332 // Sort in output order. | 1335 // Sort in output order. |
| 1333 std::sort(not_outputted.begin(), not_outputted.end(), POCAscCompare()); | 1336 std::sort(not_outputted.begin(), not_outputted.end(), POCAscCompare()); |
| 1334 | 1337 |
| 1335 // Try to output as many pictures as we can. A picture can be output | 1338 // Try to output as many pictures as we can. A picture can be output, |
| 1336 // if its POC is next after the previously outputted one (which means | 1339 // if the number of decoded and not yet outputted pictures that would remain |
| 1337 // last_output_poc_ + 2, because POCs are incremented by 2 to accommodate | 1340 // in DPB afterwards would at least be equal to max_num_reorder_frames. |
| 1338 // fields when decoding interleaved streams). POC can also be equal to | |
| 1339 // last outputted picture's POC when it wraps around back to 0. | |
| 1340 // If the outputted picture is not a reference picture, it doesn't have | 1341 // If the outputted picture is not a reference picture, it doesn't have |
| 1341 // to remain in the DPB and can be removed. | 1342 // to remain in the DPB and can be removed. |
| 1342 H264Picture::PtrVector::iterator output_candidate = not_outputted.begin(); | 1343 H264Picture::PtrVector::iterator output_candidate = not_outputted.begin(); |
| 1343 for (; output_candidate != not_outputted.end() && | 1344 size_t num_remaining = not_outputted.size(); |
| 1344 (*output_candidate)->pic_order_cnt <= last_output_poc_ + 2; | 1345 while (num_remaining > max_num_reorder_frames_) { |
| 1345 ++output_candidate) { | |
| 1346 int poc = (*output_candidate)->pic_order_cnt; | 1346 int poc = (*output_candidate)->pic_order_cnt; |
| 1347 DCHECK_GE(poc, last_output_poc_); | 1347 DCHECK_GE(poc, last_output_poc_); |
| 1348 if (!OutputPic(*output_candidate)) | 1348 if (!OutputPic(*output_candidate)) |
| 1349 return false; | 1349 return false; |
| 1350 | 1350 |
| 1351 if (!(*output_candidate)->ref) { | 1351 if (!(*output_candidate)->ref) { |
| 1352 // Current picture hasn't been inserted into DPB yet, so don't remove it | 1352 // Current picture hasn't been inserted into DPB yet, so don't remove it |
| 1353 // if we managed to output it immediately. | 1353 // if we managed to output it immediately. |
| 1354 if (*output_candidate != pic) | 1354 if (*output_candidate != pic) |
| 1355 dpb_.DeleteByPOC(poc); | 1355 dpb_.DeleteByPOC(poc); |
| 1356 // Mark as unused. | 1356 // Mark as unused. |
| 1357 UnassignSurfaceFromPoC(poc); | 1357 UnassignSurfaceFromPoC(poc); |
| 1358 } | 1358 } |
| 1359 |
| 1360 ++output_candidate; |
| 1361 --num_remaining; |
| 1359 } | 1362 } |
| 1360 | 1363 |
| 1361 // If we haven't managed to output the picture that we just decoded, or if | 1364 // If we haven't managed to output the picture that we just decoded, or if |
| 1362 // it's a reference picture, we have to store it in DPB. | 1365 // it's a reference picture, we have to store it in DPB. |
| 1363 if (!pic->outputted || pic->ref) { | 1366 if (!pic->outputted || pic->ref) { |
| 1364 if (dpb_.IsFull()) { | 1367 if (dpb_.IsFull()) { |
| 1365 // If we haven't managed to output anything to free up space in DPB | 1368 // If we haven't managed to output anything to free up space in DPB |
| 1366 // to store this picture, it's an error in the stream. | 1369 // to store this picture, it's an error in the stream. |
| 1367 DVLOG(1) << "Could not free up space in DPB!"; | 1370 DVLOG(1) << "Could not free up space in DPB!"; |
| 1368 return false; | 1371 return false; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1392 case 42: return 34816; | 1395 case 42: return 34816; |
| 1393 case 50: return 110400; | 1396 case 50: return 110400; |
| 1394 case 51: // fallthrough | 1397 case 51: // fallthrough |
| 1395 case 52: return 184320; | 1398 case 52: return 184320; |
| 1396 default: | 1399 default: |
| 1397 DVLOG(1) << "Invalid codec level (" << level << ")"; | 1400 DVLOG(1) << "Invalid codec level (" << level << ")"; |
| 1398 return 0; | 1401 return 0; |
| 1399 } | 1402 } |
| 1400 } | 1403 } |
| 1401 | 1404 |
| 1405 bool VaapiH264Decoder::UpdateMaxNumReorderFrames(const media::H264SPS* sps) { |
| 1406 if (sps->vui_parameters_present_flag && sps->bitstream_restriction_flag) { |
| 1407 max_num_reorder_frames_ = |
| 1408 base::checked_cast<size_t>(sps->max_num_reorder_frames); |
| 1409 if (max_num_reorder_frames_ > dpb_.max_num_pics()) { |
| 1410 DVLOG(1) |
| 1411 << "max_num_reorder_frames present, but larger than MaxDpbFrames (" |
| 1412 << max_num_reorder_frames_ << " > " << dpb_.max_num_pics() << ")"; |
| 1413 max_num_reorder_frames_ = 0; |
| 1414 return false; |
| 1415 } |
| 1416 return true; |
| 1417 } |
| 1418 |
| 1419 // max_num_reorder_frames not present, infer from profile/constraints |
| 1420 // (see VUI semantics in spec). |
| 1421 if (sps->constraint_set3_flag) { |
| 1422 switch (sps->profile_idc) { |
| 1423 case 44: |
| 1424 case 86: |
| 1425 case 100: |
| 1426 case 110: |
| 1427 case 122: |
| 1428 case 244: |
| 1429 max_num_reorder_frames_ = 0; |
| 1430 break; |
| 1431 default: |
| 1432 max_num_reorder_frames_ = dpb_.max_num_pics(); |
| 1433 break; |
| 1434 } |
| 1435 } else { |
| 1436 max_num_reorder_frames_ = dpb_.max_num_pics(); |
| 1437 } |
| 1438 |
| 1439 return true; |
| 1440 } |
| 1441 |
| 1402 bool VaapiH264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) { | 1442 bool VaapiH264Decoder::ProcessSPS(int sps_id, bool* need_new_buffers) { |
| 1403 const media::H264SPS* sps = parser_.GetSPS(sps_id); | 1443 const media::H264SPS* sps = parser_.GetSPS(sps_id); |
| 1404 DCHECK(sps); | 1444 DCHECK(sps); |
| 1405 DVLOG(4) << "Processing SPS"; | 1445 DVLOG(4) << "Processing SPS"; |
| 1406 | 1446 |
| 1407 *need_new_buffers = false; | 1447 *need_new_buffers = false; |
| 1408 | 1448 |
| 1409 if (sps->frame_mbs_only_flag == 0) { | 1449 if (sps->frame_mbs_only_flag == 0) { |
| 1410 DVLOG(1) << "frame_mbs_only_flag != 1 not supported"; | 1450 DVLOG(1) << "frame_mbs_only_flag != 1 not supported"; |
| 1411 report_error_to_uma_cb_.Run(FRAME_MBS_ONLY_FLAG_NOT_ONE); | 1451 report_error_to_uma_cb_.Run(FRAME_MBS_ONLY_FLAG_NOT_ONE); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1452 size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb), | 1492 size_t max_dpb_size = std::min(max_dpb_mbs / (width_mb * height_mb), |
| 1453 static_cast<int>(H264DPB::kDPBMaxSize)); | 1493 static_cast<int>(H264DPB::kDPBMaxSize)); |
| 1454 DVLOG(1) << "Codec level: " << level << ", DPB size: " << max_dpb_size; | 1494 DVLOG(1) << "Codec level: " << level << ", DPB size: " << max_dpb_size; |
| 1455 if (max_dpb_size == 0) { | 1495 if (max_dpb_size == 0) { |
| 1456 DVLOG(1) << "Invalid DPB Size"; | 1496 DVLOG(1) << "Invalid DPB Size"; |
| 1457 return false; | 1497 return false; |
| 1458 } | 1498 } |
| 1459 | 1499 |
| 1460 dpb_.set_max_num_pics(max_dpb_size); | 1500 dpb_.set_max_num_pics(max_dpb_size); |
| 1461 | 1501 |
| 1502 if (!UpdateMaxNumReorderFrames(sps)) |
| 1503 return false; |
| 1504 DVLOG(1) << "max_num_reorder_frames: " << max_num_reorder_frames_; |
| 1505 |
| 1462 *need_new_buffers = true; | 1506 *need_new_buffers = true; |
| 1463 return true; | 1507 return true; |
| 1464 } | 1508 } |
| 1465 | 1509 |
| 1466 bool VaapiH264Decoder::ProcessPPS(int pps_id) { | 1510 bool VaapiH264Decoder::ProcessPPS(int pps_id) { |
| 1467 const media::H264PPS* pps = parser_.GetPPS(pps_id); | 1511 const media::H264PPS* pps = parser_.GetPPS(pps_id); |
| 1468 DCHECK(pps); | 1512 DCHECK(pps); |
| 1469 | 1513 |
| 1470 curr_pps_id_ = pps->pic_parameter_set_id; | 1514 curr_pps_id_ = pps->pic_parameter_set_id; |
| 1471 | 1515 |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1637 break; | 1681 break; |
| 1638 } | 1682 } |
| 1639 } | 1683 } |
| 1640 } | 1684 } |
| 1641 | 1685 |
| 1642 size_t VaapiH264Decoder::GetRequiredNumOfPictures() { | 1686 size_t VaapiH264Decoder::GetRequiredNumOfPictures() { |
| 1643 return dpb_.max_num_pics() + kPicsInPipeline; | 1687 return dpb_.max_num_pics() + kPicsInPipeline; |
| 1644 } | 1688 } |
| 1645 | 1689 |
| 1646 } // namespace content | 1690 } // namespace content |
| OLD | NEW |