Chromium Code Reviews| Index: content/common/gpu/media/vaapi_jpeg_parser.cc |
| diff --git a/content/common/gpu/media/vaapi_jpeg_parser.cc b/content/common/gpu/media/vaapi_jpeg_parser.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4f86efad6ce4207379489647ee8472d099cb4e19 |
| --- /dev/null |
| +++ b/content/common/gpu/media/vaapi_jpeg_parser.cc |
| @@ -0,0 +1,291 @@ |
| +// Copyright 2014 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. |
| + |
| +#include "base/big_endian.h" |
|
wuchengli
2014/12/08 09:25:10
vaapi_jpeg_parser.h already includes this. remove
kcwu
2014/12/16 06:23:53
Done.
|
| +#include "base/logging.h" |
| +#include "content/common/gpu/media/vaapi_jpeg_parser.h" |
| + |
| +using base::BigEndianReader; |
| + |
| +namespace content { |
| + |
| +VaapiJpegParser::VaapiJpegParser(const uint8_t* buffer, size_t length) |
| + : buffer_(buffer), length_(length) { |
| +} |
| + |
| +VaapiJpegParser::~VaapiJpegParser() { |
| +} |
| + |
| +bool VaapiJpegParser::ParseSOF(BigEndianReader reader) { |
| + // Spec B.2.2 Frame header syntax |
| + uint8_t precision; |
| + |
| + if (!reader.ReadU8(&precision)) |
| + return false; |
| + if (!reader.ReadU16(&result_.visible_height)) |
| + return false; |
| + if (!reader.ReadU16(&result_.visible_width)) |
| + return false; |
| + if (!reader.ReadU8(&result_.num_component)) |
| + return false; |
| + |
| + if (precision != 8) { |
| + DLOG(ERROR) << "Only support 8 bit precision"; |
|
wuchengli
2014/12/08 09:25:11
print the actual precision
kcwu
2014/12/16 06:23:54
Done.
|
| + return false; |
| + } |
| + if (result_.num_component != 3 || |
| + result_.num_component >= arraysize(result_.components)) |
|
wuchengli
2014/12/08 09:25:10
add DLOG
kcwu
2014/12/16 06:23:53
Done.
|
| + return false; |
| + |
| + // 64k*64k is max. in the JPEG standard. VAAPI doesn't support larger than |
|
wuchengli
2014/12/08 09:25:10
s/max./the maximum/. s/64k*64k/Size 64k*64k/
kcwu
2014/12/16 06:23:53
Done.
|
| + // 16k*16k. |
| + if (result_.visible_height > 16384 || result_.visible_width > 16384) { |
|
wuchengli
2014/12/08 09:25:10
Should 16384 come from va.h or somewhere else?
kcwu
2014/12/16 06:23:53
There is no contant from va.h for this. It's heard
|
| + DLOG(ERROR) << "VAAPI don't support size larger than 16k*16k"; |
|
wuchengli
2014/12/08 09:25:10
print the actual size
kcwu
2014/12/16 06:23:54
Done.
|
| + return false; |
| + } |
| + |
| + for (int i = 0; i < result_.num_component; i++) { |
| + JpegComponent* component = &result_.components[i]; |
|
wuchengli
2014/12/08 09:25:10
nit: use JpegComponent&?
kcwu
2014/12/16 06:23:53
Done.
|
| + if (!reader.ReadU8(&component->id)) |
| + return false; |
| + if (component->id > result_.num_component) { |
| + DLOG(ERROR) << "Only allow component id <= num_component: " |
|
wuchengli
2014/12/08 09:25:11
Print both numbers at the end is not very clear. M
kcwu
2014/12/16 06:23:54
Done.
|
| + << static_cast<int>(component->id) << "," |
| + << static_cast<int>(result_.num_component); |
| + return false; |
| + } |
| + uint8_t hv; |
|
wuchengli
2014/12/08 09:25:10
Is hv a common Jpeg terminology? If not, use more
kcwu
2014/12/16 06:23:54
It's not so meaningful to give a name for this. Th
|
| + if (!reader.ReadU8(&hv)) |
| + return false; |
| + component->horizontal_sampling_factor = hv / 16; |
| + component->vertical_sampling_factor = hv % 16; |
| + if (!reader.ReadU8(&component->quantization_table_selector)) |
| + return false; |
| + } |
| + |
| + if (result_.components[0].horizontal_sampling_factor < |
| + result_.components[1].horizontal_sampling_factor || |
| + result_.components[0].horizontal_sampling_factor < |
| + result_.components[2].horizontal_sampling_factor) { |
| + DLOG(ERROR) << "VAAPI don't supports horizontal sampling factor of Y" |
| + << " smaller than Cb and Cr"; |
| + return false; |
| + } |
| + if (result_.components[0].vertical_sampling_factor < |
| + result_.components[1].vertical_sampling_factor || |
| + result_.components[0].vertical_sampling_factor < |
| + result_.components[2].vertical_sampling_factor) { |
| + DLOG(ERROR) << "VAAPI don't supports vertical sampling factor of Y" |
| + << " smaller than Cb and Cr"; |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool VaapiJpegParser::ParseDQT(BigEndianReader reader) { |
| + // Spec B.2.4.1 Quantization table-specification syntax |
| + while (reader.remaining() > 0) { |
| + uint8_t tmp; |
| + if (!reader.ReadU8(&tmp)) |
| + return false; |
| + uint8_t precision = tmp / 16; |
| + uint8_t table_id = tmp % 16; |
| + if (precision != 0) { |
| + DLOG(ERROR) << "16 bits quantization table is not supported"; |
| + return false; |
| + } |
| + if (table_id >= kJpegQuantizationTableNum) |
| + return false; |
| + |
| + if (!reader.ReadBytes(&result_.q_table[table_id].value, |
| + sizeof(result_.q_table[table_id].value))) |
| + return false; |
| + result_.q_table[table_id].valid = true; |
| + } |
| + return true; |
| +} |
| + |
| +bool VaapiJpegParser::ParseDHT(BigEndianReader reader) { |
| + // Spec B.2.4.2 Huffman table-specification syntax |
| + while (reader.remaining() > 0) { |
| + uint8_t t; |
| + if (!reader.ReadU8(&t)) |
| + return false; |
| + int table_class = t / 16; |
| + int table_id = t % 16; |
| + if (table_class >= 2) // invalid |
|
wuchengli
2014/12/08 09:25:10
Add DLOG. Add DLOG for all non reader.ReadU8 failu
kcwu
2014/12/16 06:23:54
Done.
|
| + return false; |
| + if (table_id >= 2) // only support baseline |
|
wuchengli
2014/12/08 09:25:10
Add DLOG
kcwu
2014/12/16 06:23:54
Done.
|
| + return false; |
| + |
| + bool is_ac_table = (table_class == 1); |
| + JpegHuffmanTable* table; |
| + if (is_ac_table) |
|
wuchengli
2014/12/08 09:25:10
just use table_class == 1 here?
kcwu
2014/12/16 06:23:54
Done.
|
| + table = &result_.ac_table[table_id]; |
| + else |
| + table = &result_.dc_table[table_id]; |
| + |
| + size_t count = 0; |
| + if (!reader.ReadBytes(&table->code_length, sizeof(table->code_length))) |
| + return false; |
| + for (unsigned i = 0; i < arraysize(table->code_length); i++) |
|
wuchengli
2014/12/08 09:25:10
s/unsigned/size_t/
kcwu
2014/12/16 06:23:53
Done.
|
| + count += table->code_length[i]; |
| + |
| + if (count > sizeof(table->code_value)) |
|
wuchengli
2014/12/08 09:25:11
add DLOG
kcwu
2014/12/16 06:23:53
Done.
|
| + return false; |
| + if (!reader.ReadBytes(&table->code_value, count)) |
| + return false; |
| + table->valid = true; |
| + } |
| + return true; |
| +} |
| + |
| +bool VaapiJpegParser::ParseDRI(BigEndianReader reader) { |
| + // Spec B.2.4.4 Restart interval definition syntax |
| + return reader.ReadU16(&result_.restart_interval) && reader.remaining() == 0; |
| +} |
| + |
| +bool VaapiJpegParser::ParseSOS(BigEndianReader reader) { |
| + // Spec B.2.3 Scan header syntax |
| + if (!reader.ReadU8(&result_.scan.num_component)) |
| + return false; |
| + if (result_.scan.num_component != result_.num_component) |
|
wuchengli
2014/12/08 09:25:10
add DLOG
kcwu
2014/12/16 06:23:54
Done.
|
| + return false; |
| + |
| + for (int i = 0; i < result_.scan.num_component; i++) { |
| + JpegScan::Component* component = &result_.scan.components[i]; |
| + if (!reader.ReadU8(&component->component_selector)) |
| + return false; |
| + uint8_t tmp; |
| + if (!reader.ReadU8(&tmp)) |
| + return false; |
| + component->dc_selector = tmp / 16; |
| + component->ac_selector = tmp % 16; |
| + if (component->component_selector != result_.components[i].id) |
| + return false; |
| + if (component->dc_selector >= kJpegHuffmanTableNum) |
| + return false; |
| + if (component->ac_selector >= kJpegHuffmanTableNum) |
| + return false; |
| + } |
| + |
| + // unused fields, only for value checking |
| + uint8_t spectral_selection_start; |
| + uint8_t spectral_selection_end; |
| + uint8_t point_transform; |
| + if (!reader.ReadU8(&spectral_selection_start)) |
| + return false; |
| + if (!reader.ReadU8(&spectral_selection_end)) |
| + return false; |
| + if (!reader.ReadU8(&point_transform)) |
| + return false; |
| + if (spectral_selection_start != 0 || spectral_selection_end != 63) { |
| + DLOG(ERROR) << "Spectral selection should be 0,63 for baseline mode"; |
| + return false; |
| + } |
| + if (point_transform != 0) { |
| + DLOG(ERROR) << "Point transform should be 0 for baseline mode"; |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool VaapiJpegParser::ParseSOI(BigEndianReader reader) { |
| + // Spec B.2.1 High-level syntax |
| + uint8_t marker1; |
| + uint8_t marker2; |
| + bool has_marker_dqt = false; |
| + bool has_marker_sos = false; |
| + |
| + // Once reached SOS, all neccesary data are parsed. |
| + while (!has_marker_sos) { |
| + if (!reader.ReadU8(&marker1) || marker1 != MARKER1) |
| + return false; |
| + |
| + do { |
| + if (!reader.ReadU8(&marker2)) |
| + return false; |
| + } while (marker2 == MARKER1); // skip padding |
| + |
| + uint16_t size; |
| + if (!reader.ReadU16(&size)) |
| + return false; |
| + if (reader.remaining() < size) |
|
wuchengli
2014/12/08 09:25:10
add DLOG
kcwu
2014/12/16 06:23:54
Done.
|
| + return false; |
| + |
| + // The size includes the size field itself. |
| + if (size < sizeof(size)) |
|
wuchengli
2014/12/08 09:25:10
add DLOG
kcwu
2014/12/16 06:23:54
Done.
|
| + return false; |
| + size -= sizeof(size); |
| + |
| + switch (marker2) { |
| + case SOF0: |
| + if (!ParseSOF(BigEndianReader(reader.ptr(), size))) { |
| + DLOG(ERROR) << "ParseSOF failed"; |
| + return false; |
| + } |
| + break; |
| + case DQT: |
| + if (!ParseDQT(BigEndianReader(reader.ptr(), size))) { |
| + DLOG(ERROR) << "ParseDQT failed"; |
| + return false; |
| + } |
| + has_marker_dqt = true; |
| + break; |
| + case DHT: |
| + if (!ParseDHT(BigEndianReader(reader.ptr(), size))) { |
| + DLOG(ERROR) << "ParseDHT failed"; |
| + return false; |
| + } |
| + break; |
| + case DRI: |
| + if (!ParseDRI(BigEndianReader(reader.ptr(), size))) { |
| + DLOG(ERROR) << "ParseDRI failed"; |
| + return false; |
| + } |
| + break; |
| + case SOS: |
| + if (!ParseSOS(BigEndianReader(reader.ptr(), size))) { |
| + DLOG(ERROR) << "ParseSOS failed"; |
| + return false; |
| + } |
| + has_marker_sos = true; |
| + break; |
| + default: |
| + DVLOG(4) << "unknown marker " << static_cast<int>(marker2); |
|
wuchengli
2014/12/08 09:25:10
Why do we need this cast?
kcwu
2014/12/16 06:23:53
marker2 is char. It will print the character if no
|
| + break; |
| + } |
| + reader.Skip(size); |
| + } |
| + |
| + if (!has_marker_dqt) { |
| + DLOG(ERROR) << "No DQT marker found"; |
| + return false; |
| + } |
| + |
| + // Scan data is following scan header immediately. |
|
wuchengli
2014/12/08 09:25:11
s/is following/follows/
kcwu
2014/12/16 06:23:54
Done.
|
| + result_.scan.data = reader.ptr(); |
| + result_.scan.data_size = reader.remaining(); |
| + |
| + return true; |
| +} |
| + |
| +bool VaapiJpegParser::Parse() { |
| + BigEndianReader reader(reinterpret_cast<const char*>(buffer_), length_); |
| + memset(&result_, 0, sizeof(result_)); |
| + |
| + uint8_t marker1; |
| + uint8_t marker2; |
|
wuchengli
2014/12/08 09:25:10
nit: combine with the previous line
kcwu
2014/12/16 06:23:53
Done.
|
| + if (!reader.ReadU8(&marker1) || marker1 != MARKER1 || |
| + !reader.ReadU8(&marker2) || marker2 != SOI) { |
| + LOG(ERROR) << "Not a JPEG"; |
| + return false; |
| + } |
| + |
| + return ParseSOI(BigEndianReader(reader.ptr(), reader.remaining())); |
| +} |
| + |
| +} // namespace content |