mirror of https://bitbucket.org/ausocean/av.git
Merge branch 'master' into audio-player
This commit is contained in:
commit
f46282ea15
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
NAME
|
||||
adpcm.js
|
||||
|
||||
AUTHOR
|
||||
Trek Hopton <trek@ausocean.org>
|
||||
|
||||
LICENSE
|
||||
This file is Copyright (C) 2018 the Australian Ocean Lab (AusOcean)
|
||||
|
||||
It is free software: you can redistribute it and/or modify them
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License in gpl.txt.
|
||||
If not, see [GNU licenses](http://www.gnu.org/licenses).
|
||||
*/
|
||||
|
||||
/*
|
||||
Original IMA/DVI ADPCM specification: (http://www.cs.columbia.edu/~hgs/audio/dvi/IMA_ADPCM.pdf).
|
||||
Reference algorithms for ADPCM compression and decompression are in part 6.
|
||||
*/
|
||||
|
||||
// Table of index changes (see spec).
|
||||
const indexTable = [
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
];
|
||||
|
||||
// Quantize step size table (see spec).
|
||||
const stepTable = [
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
16, 17, 19, 21, 23, 25, 28, 31,
|
||||
34, 37, 41, 45, 50, 55, 60, 66,
|
||||
73, 80, 88, 97, 107, 118, 130, 143,
|
||||
157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
||||
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
||||
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||
32767
|
||||
];
|
||||
|
||||
const byteDepth = 2; // We are working with 16-bit samples. TODO(Trek): make configurable.
|
||||
const headSize = 8; // Number of bytes in the header of ADPCM.
|
||||
const chunkLenSize = 4;
|
||||
|
||||
let est = 0; // Estimation of sample based on quantised ADPCM nibble.
|
||||
let idx = 0; // Index to step used for estimation.
|
||||
let step = 0;
|
||||
|
||||
// decodeSample takes 4 bits which represents a single ADPCM nibble, and returns a 16 bit decoded PCM sample.
|
||||
function decodeSample(nibble) {
|
||||
let diff = 0;
|
||||
if ((nibble & 4) != 0) {
|
||||
diff += step;
|
||||
}
|
||||
if ((nibble & 2) != 0) {
|
||||
diff += step >> 1;
|
||||
}
|
||||
if ((nibble & 1) != 0) {
|
||||
diff += step >> 2;
|
||||
}
|
||||
diff += step >> 3;
|
||||
|
||||
if ((nibble & 8) != 0) {
|
||||
diff = -diff;
|
||||
}
|
||||
est += diff;
|
||||
idx += indexTable[nibble];
|
||||
|
||||
if (idx < 0) {
|
||||
idx = 0;
|
||||
} else if (idx > stepTable.length - 1) {
|
||||
idx = stepTable.length - 1;
|
||||
}
|
||||
|
||||
step = stepTable[idx];
|
||||
|
||||
result = est;
|
||||
return result;
|
||||
}
|
||||
|
||||
// decode takes an array of bytes of arbitrary length representing adpcm and decodes it into pcm.
|
||||
function decode(b) {
|
||||
// Iterate over each chunk and decode it.
|
||||
let chunkLen;
|
||||
var result = [];
|
||||
for (var off = 0; off + headSize <= b.length; off += chunkLen) {
|
||||
// Read length of chunk and check if whole chunk exists.
|
||||
chunkLen = bytesToInt32(b.slice(off, off + chunkLenSize))
|
||||
if (off + chunkLen > b.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Initialize Decoder with first 4 bytes of b.
|
||||
est = bytesToInt16(b.slice(off + chunkLenSize, off + chunkLenSize + byteDepth));
|
||||
idx = b[off + chunkLenSize + byteDepth];
|
||||
step = stepTable[idx];
|
||||
|
||||
result.push(...b.slice(off + chunkLenSize, off + chunkLenSize + byteDepth));
|
||||
|
||||
for (var i = off + headSize; i < off + chunkLen - b[off + chunkLenSize + 3]; i++) {
|
||||
var twoNibs = b[i];
|
||||
var nib2 = twoNibs >> 4;
|
||||
var nib1 = (nib2 << 4) ^ twoNibs;
|
||||
|
||||
var sample1 = int16ToBytes(decodeSample(nib1));
|
||||
result.push(...sample1);
|
||||
|
||||
var sample2 = int16ToBytes(decodeSample(nib2));
|
||||
result.push(...sample2);
|
||||
}
|
||||
if (b[off + chunkLenSize + 3] == 1) {
|
||||
var padNib = b[off + chunkLen - 1];
|
||||
var sample = int16ToBytes(decodeSample(padNib));
|
||||
result.push(...sample);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// int16ToBytes takes a number assumed to be an int 16 and converts it to an array containing bytes (Little Endian).
|
||||
function int16ToBytes(num) {
|
||||
return [(num & 0x00ff), (num & 0xff00) >> 8];
|
||||
}
|
||||
|
||||
// bytesToInt16 takes an array of bytes (assumed to be values between 0 and 255), interprates them as little endian and converts it to an int16.
|
||||
function bytesToInt16(b) {
|
||||
return (b[0] | (b[1] << 8));
|
||||
}
|
||||
|
||||
// bytesToInt32 takes an array of bytes (assumed to be values between 0 and 255), interprates them as little endian and converts it to an int32.
|
||||
function bytesToInt32(b) {
|
||||
return (b[0] |
|
||||
(b[1] << 8) |
|
||||
(b[2] << 16) |
|
||||
(b[3] << 24));
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
|
@ -1,44 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Audio Player</title>
|
||||
<script type="text/javascript" src="pcm-to-wav.js"></script>
|
||||
<script type="text/javascript" src="adpcm.js"></script>
|
||||
<script type="text/javascript" src="main.js"></script>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
</head>
|
||||
|
||||
<body style="height: 100%" onload="load();">
|
||||
<div class="card m-auto" style="width: 40rem;">
|
||||
<div class="card-body">
|
||||
<div class="container-fluid">
|
||||
URL: <input type="text" id="url" class="url mb-3 mx-3" onchange="load();"><button onclick="load();">Load</button>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<a id="link" href=""></a>
|
||||
</div>
|
||||
<div style="height: 1rem">
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div class="form-group">
|
||||
<input class="form-control-file" type="file" id="fileinput" onchange="processData();">
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<audio class="mx-auto" controls="controls" id="audio">
|
||||
Your browser does not support the <code>audio</code> element.
|
||||
<source id="source" src="" type="audio/wav" />
|
||||
</audio>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer id="sticky-footer" class="footer fixed-bottom py-4 bg-dark text-white-50" style="width: 100%;">
|
||||
<div class="container text-center">
|
||||
<small>©2019 Australian Ocean Laboratory Limited (AusOcean) (<a rel="license" href="https://www.ausocean.org/license">License</a>)</small>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
NAME
|
||||
main.js
|
||||
|
||||
AUTHOR
|
||||
Trek Hopton <trek@ausocean.org>
|
||||
Alan Noble <alan@ausocean.org>
|
||||
|
||||
LICENSE
|
||||
This file is Copyright (C) 2018 the Australian Ocean Lab (AusOcean)
|
||||
|
||||
It is free software: you can redistribute it and/or modify them
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License in gpl.txt.
|
||||
If not, see [GNU licenses](http://www.gnu.org/licenses).
|
||||
*/
|
||||
|
||||
function processData() {
|
||||
const input = event.target.files[0]
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onload = event => {
|
||||
bytes = new Uint8Array(event.target.result)
|
||||
|
||||
// decode adpcm to pcm
|
||||
var decoded = decode(Array.from(bytes))
|
||||
|
||||
// convert raw pcm to wav TODO(Trek): make these configurable.
|
||||
var wav = pcmToWav(decoded, 48000, 1, 16);
|
||||
|
||||
// play wav data in player
|
||||
const blob = new Blob([Uint8Array.from(wav)], {
|
||||
type: 'audio/wav'
|
||||
});
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const audio = document.getElementById('audio');
|
||||
const source = document.getElementById('source');
|
||||
|
||||
source.src = url;
|
||||
audio.load();
|
||||
audio.play();
|
||||
}
|
||||
reader.onerror = error => reject(error)
|
||||
reader.readAsArrayBuffer(input)
|
||||
|
||||
}
|
||||
|
||||
// getQuery gets everything after the question mark in the URL.
|
||||
function getQuery() {
|
||||
var regex = new RegExp("\\?(.*)");
|
||||
var match = regex.exec(window.location.href);
|
||||
if (match == null) {
|
||||
return '';
|
||||
} else {
|
||||
return decodeURIComponent(match[1].replace(/\+/g, " "));
|
||||
}
|
||||
}
|
||||
|
||||
function load() {
|
||||
var url = document.getElementById('url').value;
|
||||
if (url == "") {
|
||||
url = getQuery()
|
||||
document.getElementById('url').value = url;
|
||||
}
|
||||
if (url[0] == '/') {
|
||||
url = window.location.protocol + '//' + window.location.host + url;
|
||||
}
|
||||
if (url == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.responseType = "blob";
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState === XMLHttpRequest.DONE) {
|
||||
if (request.status === 200) {
|
||||
console.log("request received");
|
||||
|
||||
data = request.response;
|
||||
|
||||
dataURL = URL.createObjectURL(data);
|
||||
|
||||
var link = document.getElementById("link");
|
||||
link.href = dataURL;
|
||||
link.download = "media.ts";
|
||||
link.innerHTML = "Download";
|
||||
|
||||
} else {
|
||||
console.log('There was a problem with the request. Status: ' + request.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
request.open("GET", url, true);
|
||||
request.send();
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
NAME
|
||||
pcm-to-wav.js
|
||||
|
||||
AUTHOR
|
||||
Trek Hopton <trek@ausocean.org>
|
||||
|
||||
LICENSE
|
||||
This file is Copyright (C) 2018 the Australian Ocean Lab (AusOcean)
|
||||
|
||||
It is free software: you can redistribute it and/or modify them
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License in gpl.txt.
|
||||
If not, see [GNU licenses](http://www.gnu.org/licenses).
|
||||
*/
|
||||
|
||||
// pcmToWav takes raw pcm data along with the sample rate, number of channels and bit-depth,
|
||||
// and adds a WAV header to it so that it can be read and played by common players.
|
||||
// input and output data bytes are represented as arrays of 8 bit integers.
|
||||
// WAV spec.: http://soundfile.sapp.org/doc/WaveFormat/
|
||||
function pcmToWav(data, rate, channels, bitdepth) {
|
||||
subChunk2ID = [100, 97, 116, 97]; // "data"
|
||||
subChunk2Size = int32ToBytes(data.length);
|
||||
|
||||
subChunk1ID = [102, 109, 116, 32]; // "fmt "
|
||||
subChunk1Size = int32ToBytes(16);
|
||||
audioFmt = int16ToBytes(1); // 1 = PCM
|
||||
numChannels = int16ToBytes(channels);
|
||||
sampleRate = int32ToBytes(rate);
|
||||
byteRate = int32ToBytes(rate * channels * bitdepth / 8);
|
||||
blockAlign = int16ToBytes(channels * bitdepth / 8);
|
||||
bitsPerSample = int16ToBytes(bitdepth)
|
||||
|
||||
chunkID = [82, 73, 70, 70]; // "RIFF"
|
||||
chunkSize = int32ToBytes(36 + data.length);
|
||||
format = [87, 65, 86, 69]; // "WAVE"
|
||||
|
||||
result = chunkID;
|
||||
result.push(...chunkSize, ...format, ...subChunk1ID, ...subChunk1Size, ...audioFmt, ...numChannels, ...sampleRate, ...byteRate, ...blockAlign, ...bitsPerSample, ...subChunk2ID, ...subChunk2Size);
|
||||
return result.concat(data);
|
||||
}
|
||||
|
||||
// int32ToBytes takes a number assumed to be an int 32 and converts it to an array containing bytes (Little Endian).
|
||||
function int32ToBytes(num) {
|
||||
return [
|
||||
(num & 0x000000ff),
|
||||
(num & 0x0000ff00) >> 8,
|
||||
(num & 0x00ff0000) >> 16,
|
||||
(num & 0xff000000) >> 24
|
||||
];
|
||||
}
|
||||
|
||||
// int16ToBytes takes a number assumed to be an int 16 and converts it to an array containing bytes (Little Endian).
|
||||
function int16ToBytes(num) {
|
||||
return [(num & 0x00ff), (num & 0xff00) >> 8];
|
||||
}
|
|
@ -369,7 +369,7 @@ func capAdd16(a, b int16) int16 {
|
|||
// EncBytes will return the number of adpcm bytes that will be generated when encoding the given amount of pcm bytes (n).
|
||||
func EncBytes(n int) int {
|
||||
// For 'n' pcm bytes, 1 sample is left uncompressed, the rest is compressed by a factor of 4
|
||||
// and a start index and padding-flag byte are added.
|
||||
// and a chunk length (4B), start index (1B) and padding-flag (1B) are added.
|
||||
// Also if there are an even number of samples, there will be half a byte of padding added to the last byte.
|
||||
if n%bytesPerEnc == 0 {
|
||||
return (n-byteDepth)/compFact + headSize + 1
|
||||
|
|
|
@ -171,7 +171,7 @@ type CABAC struct {
|
|||
}
|
||||
|
||||
// table 9-1
|
||||
func initCabac(binarization *Binarization, context *SliceContext) *CABAC {
|
||||
func initCabac(binarization *Binarization, vid *VideoStream, ctx *SliceContext) *CABAC {
|
||||
var valMPS, pStateIdx int
|
||||
// TODO: When to use prefix, when to use suffix?
|
||||
ctxIdx := CtxIdx(
|
||||
|
@ -180,7 +180,7 @@ func initCabac(binarization *Binarization, context *SliceContext) *CABAC {
|
|||
binarization.CtxIdxOffset.Prefix)
|
||||
mn := MNVars[ctxIdx]
|
||||
|
||||
preCtxState := PreCtxState(mn[0].M, mn[0].N, SliceQPy(context.PPS, context.Header))
|
||||
preCtxState := PreCtxState(mn[0].M, mn[0].N, SliceQPy(vid.PPS, ctx.SliceHeader))
|
||||
if preCtxState <= 63 {
|
||||
pStateIdx = 63 - preCtxState
|
||||
valMPS = 0
|
||||
|
@ -195,7 +195,7 @@ func initCabac(binarization *Binarization, context *SliceContext) *CABAC {
|
|||
return &CABAC{
|
||||
PStateIdx: pStateIdx,
|
||||
ValMPS: valMPS,
|
||||
Context: context,
|
||||
Context: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -457,7 +457,7 @@ func NewArithmeticDecoding(context *SliceContext, binarization *Binarization, ct
|
|||
if binarization.UseDecodeBypass == 1 {
|
||||
// TODO: 9.3.3.2.3 : DecodeBypass()
|
||||
var err error
|
||||
codIOffset, a.BinVal, err = a.DecodeBypass(context.Slice.Data, codIRange, codIOffset)
|
||||
codIOffset, a.BinVal, err = a.DecodeBypass(context.SliceData, codIRange, codIOffset)
|
||||
if err != nil {
|
||||
return ArithmeticDecoding{}, errors.Wrap(err, "error from DecodeBypass getting codIOffset and BinVal")
|
||||
}
|
||||
|
@ -539,7 +539,7 @@ type ArithmeticDecoding struct {
|
|||
// returns: binVal, updated codIRange, updated codIOffset
|
||||
func (a ArithmeticDecoding) BinaryDecision(ctxIdx, codIRange, codIOffset int) (int, int, int, error) {
|
||||
var binVal int
|
||||
cabac := initCabac(a.Binarization, a.Context)
|
||||
cabac := initCabac(a.Binarization, nil, a.Context)
|
||||
// Derivce codIRangeLPS
|
||||
qCodIRangeIdx := (codIRange >> 6) & 3
|
||||
pStateIdx := cabac.PStateIdx
|
||||
|
|
|
@ -26,6 +26,7 @@ LICENSE
|
|||
package h264dec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
|
||||
|
@ -44,3 +45,103 @@ func parseLevelPrefix(br *bits.BitReader) (int, error) {
|
|||
}
|
||||
return zeros, nil
|
||||
}
|
||||
|
||||
// parseLevelInformation parses level information and returns the resultant
|
||||
// levelVal list using the process defined by section 9.2.2 in the specifications.
|
||||
func parseLevelInformation(br *bits.BitReader, totalCoeff, trailingOnes int) ([]int, error) {
|
||||
var levelVal []int
|
||||
var i int
|
||||
for ; i < trailingOnes; i++ {
|
||||
b, err := br.ReadBits(1)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read trailing_ones_sign_flag, failed with error: %v", err)
|
||||
}
|
||||
levelVal = append(levelVal, 1-int(b)*2)
|
||||
}
|
||||
|
||||
var suffixLen int
|
||||
switch {
|
||||
case totalCoeff > 10 && trailingOnes < 3:
|
||||
suffixLen = 1
|
||||
case totalCoeff <= 10 || trailingOnes == 3:
|
||||
suffixLen = 0
|
||||
default:
|
||||
return nil, errors.New("invalid TotalCoeff and TrailingOnes combination")
|
||||
}
|
||||
|
||||
for j := 0; j < totalCoeff-trailingOnes; j++ {
|
||||
levelPrefix, err := parseLevelPrefix(br)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse level prefix, failed with error: %v", err)
|
||||
}
|
||||
|
||||
var levelSuffixSize int
|
||||
switch {
|
||||
case levelPrefix == 14 && suffixLen == 0:
|
||||
levelSuffixSize = 4
|
||||
case levelPrefix >= 15:
|
||||
levelSuffixSize = levelPrefix - 3
|
||||
default:
|
||||
levelSuffixSize = suffixLen
|
||||
}
|
||||
|
||||
var levelSuffix int
|
||||
if levelSuffixSize > 0 {
|
||||
b, err := br.ReadBits(levelSuffixSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse levelSuffix, failed with error: %v", err)
|
||||
}
|
||||
levelSuffix = int(b)
|
||||
} else {
|
||||
levelSuffix = 0
|
||||
}
|
||||
|
||||
levelCode := (mini(15, levelPrefix) << uint(suffixLen)) + levelSuffix
|
||||
|
||||
if levelPrefix >= 15 && suffixLen == 0 {
|
||||
levelCode += 15
|
||||
}
|
||||
|
||||
if levelPrefix >= 16 {
|
||||
levelCode += (1 << uint(levelPrefix-3)) - 4096
|
||||
}
|
||||
|
||||
if i == trailingOnes && trailingOnes < 3 {
|
||||
levelCode += 2
|
||||
}
|
||||
|
||||
if levelCode%2 == 0 {
|
||||
levelVal = append(levelVal, (levelCode+2)>>1)
|
||||
} else {
|
||||
levelVal = append(levelVal, (-levelCode-1)>>1)
|
||||
}
|
||||
|
||||
if suffixLen == 0 {
|
||||
suffixLen = 1
|
||||
}
|
||||
|
||||
if absi(levelVal[i]) > (3<<uint(suffixLen-1)) && suffixLen < 6 {
|
||||
suffixLen++
|
||||
}
|
||||
i++
|
||||
}
|
||||
return levelVal, nil
|
||||
}
|
||||
|
||||
// combineLevelRunInfo combines the level and run information obtained prior
|
||||
// using the process defined in section 9.2.4 of the specifications and returns
|
||||
// the corresponding coeffLevel list.
|
||||
func combineLevelRunInfo(levelVal, runVal []int, totalCoeff int) []int {
|
||||
coeffNum := -1
|
||||
i := totalCoeff - 1
|
||||
var coeffLevel []int
|
||||
for j := 0; j < totalCoeff; j++ {
|
||||
coeffNum += runVal[i] + 1
|
||||
if coeffNum >= len(coeffLevel) {
|
||||
coeffLevel = append(coeffLevel, make([]int, (coeffNum+1)-len(coeffLevel))...)
|
||||
}
|
||||
coeffLevel[coeffNum] = levelVal[i]
|
||||
i++
|
||||
}
|
||||
return coeffLevel
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
DESCRIPTION
|
||||
decode.go provides slice decoding functionality.
|
||||
|
||||
AUTHORS
|
||||
Saxon A. Nelson-Milton <saxon@ausocean.org>
|
||||
|
||||
LICENSE
|
||||
Copyright (C) 2019 the Australian Ocean Lab (AusOcean).
|
||||
|
||||
It is free software: you can redistribute it and/or modify them
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
in gpl.txt. If not, see http://www.gnu.org/licenses.
|
||||
*/
|
||||
|
||||
package h264dec
|
|
@ -11,7 +11,7 @@ const (
|
|||
naluTypeSEI
|
||||
NALTypeSPS
|
||||
naluTypePPS
|
||||
naluTypeAccessUnitDelimiter
|
||||
NALTypeAccessUnitDelimiter
|
||||
naluTypeEndOfSequence
|
||||
naluTypeEndOfStream
|
||||
naluTypeFillerData
|
||||
|
|
|
@ -36,21 +36,21 @@ const (
|
|||
)
|
||||
|
||||
type VideoStream struct {
|
||||
SPS *SPS
|
||||
PPS *PPS
|
||||
*SPS
|
||||
*PPS
|
||||
Slices []*SliceContext
|
||||
|
||||
ChromaArrayType int
|
||||
}
|
||||
|
||||
type SliceContext struct {
|
||||
*NALUnit
|
||||
*SPS
|
||||
*PPS
|
||||
*Slice
|
||||
}
|
||||
|
||||
type Slice struct {
|
||||
Header *SliceHeader
|
||||
Data *SliceData
|
||||
*SliceHeader
|
||||
*SliceData
|
||||
}
|
||||
|
||||
// RefPicListModification provides elements of a ref_pic_list_modification syntax
|
||||
|
@ -526,12 +526,12 @@ func NumMbPart(nalUnit *NALUnit, sps *SPS, header *SliceHeader, data *SliceData)
|
|||
return numMbPart
|
||||
}
|
||||
|
||||
func MbPred(chromaArrayType int, sliceContext *SliceContext, br *bits.BitReader, rbsp []byte) error {
|
||||
func MbPred(chromaArrayType int, vid *VideoStream, sliceContext *SliceContext, br *bits.BitReader, rbsp []byte) error {
|
||||
var cabac *CABAC
|
||||
r := newFieldReader(br)
|
||||
|
||||
sliceType := sliceTypeMap[sliceContext.Slice.Header.SliceType]
|
||||
mbPartPredMode, err := MbPartPredMode(sliceContext.Slice.Data, sliceType, sliceContext.Slice.Data.MbType, 0)
|
||||
sliceType := sliceTypeMap[sliceContext.Slice.SliceHeader.SliceType]
|
||||
mbPartPredMode, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceType, sliceContext.Slice.SliceData.MbType, 0)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get mbPartPredMode")
|
||||
}
|
||||
|
@ -539,14 +539,15 @@ func MbPred(chromaArrayType int, sliceContext *SliceContext, br *bits.BitReader,
|
|||
if mbPartPredMode == intra4x4 {
|
||||
for luma4x4BlkIdx := 0; luma4x4BlkIdx < 16; luma4x4BlkIdx++ {
|
||||
var v int
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: 1 bit or ae(v)
|
||||
binarization := NewBinarization(
|
||||
"PrevIntra4x4PredModeFlag",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
cabac = initCabac(binarization, sliceContext)
|
||||
// TODO: fix videostream should be nil.
|
||||
cabac = initCabac(binarization, nil, sliceContext)
|
||||
_ = cabac
|
||||
logger.Printf("TODO: ae for PevIntra4x4PredModeFlag[%d]\n", luma4x4BlkIdx)
|
||||
} else {
|
||||
|
@ -556,15 +557,15 @@ func MbPred(chromaArrayType int, sliceContext *SliceContext, br *bits.BitReader,
|
|||
}
|
||||
v = int(b)
|
||||
}
|
||||
sliceContext.Slice.Data.PrevIntra4x4PredModeFlag = append(
|
||||
sliceContext.Slice.Data.PrevIntra4x4PredModeFlag,
|
||||
sliceContext.Slice.SliceData.PrevIntra4x4PredModeFlag = append(
|
||||
sliceContext.Slice.SliceData.PrevIntra4x4PredModeFlag,
|
||||
v)
|
||||
if sliceContext.Slice.Data.PrevIntra4x4PredModeFlag[luma4x4BlkIdx] == 0 {
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if sliceContext.Slice.SliceData.PrevIntra4x4PredModeFlag[luma4x4BlkIdx] == 0 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: 3 bits or ae(v)
|
||||
binarization := NewBinarization(
|
||||
"RemIntra4x4PredMode",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
logger.Printf("TODO: ae for RemIntra4x4PredMode[%d]\n", luma4x4BlkIdx)
|
||||
|
@ -575,22 +576,22 @@ func MbPred(chromaArrayType int, sliceContext *SliceContext, br *bits.BitReader,
|
|||
}
|
||||
v = int(b)
|
||||
}
|
||||
if len(sliceContext.Slice.Data.RemIntra4x4PredMode) < luma4x4BlkIdx {
|
||||
sliceContext.Slice.Data.RemIntra4x4PredMode = append(
|
||||
sliceContext.Slice.Data.RemIntra4x4PredMode,
|
||||
make([]int, luma4x4BlkIdx-len(sliceContext.Slice.Data.RemIntra4x4PredMode)+1)...)
|
||||
if len(sliceContext.Slice.SliceData.RemIntra4x4PredMode) < luma4x4BlkIdx {
|
||||
sliceContext.Slice.SliceData.RemIntra4x4PredMode = append(
|
||||
sliceContext.Slice.SliceData.RemIntra4x4PredMode,
|
||||
make([]int, luma4x4BlkIdx-len(sliceContext.Slice.SliceData.RemIntra4x4PredMode)+1)...)
|
||||
}
|
||||
sliceContext.Slice.Data.RemIntra4x4PredMode[luma4x4BlkIdx] = v
|
||||
sliceContext.Slice.SliceData.RemIntra4x4PredMode[luma4x4BlkIdx] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
if mbPartPredMode == intra8x8 {
|
||||
for luma8x8BlkIdx := 0; luma8x8BlkIdx < 4; luma8x8BlkIdx++ {
|
||||
sliceContext.Update(sliceContext.Slice.Header, sliceContext.Slice.Data)
|
||||
sliceContext.Update(sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData)
|
||||
var v int
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: 1 bit or ae(v)
|
||||
binarization := NewBinarization("PrevIntra8x8PredModeFlag", sliceContext.Slice.Data)
|
||||
binarization := NewBinarization("PrevIntra8x8PredModeFlag", sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
logger.Printf("TODO: ae for PrevIntra8x8PredModeFlag[%d]\n", luma8x8BlkIdx)
|
||||
|
@ -601,14 +602,14 @@ func MbPred(chromaArrayType int, sliceContext *SliceContext, br *bits.BitReader,
|
|||
}
|
||||
v = int(b)
|
||||
}
|
||||
sliceContext.Slice.Data.PrevIntra8x8PredModeFlag = append(
|
||||
sliceContext.Slice.Data.PrevIntra8x8PredModeFlag, v)
|
||||
if sliceContext.Slice.Data.PrevIntra8x8PredModeFlag[luma8x8BlkIdx] == 0 {
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
sliceContext.Slice.SliceData.PrevIntra8x8PredModeFlag = append(
|
||||
sliceContext.Slice.SliceData.PrevIntra8x8PredModeFlag, v)
|
||||
if sliceContext.Slice.SliceData.PrevIntra8x8PredModeFlag[luma8x8BlkIdx] == 0 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: 3 bits or ae(v)
|
||||
binarization := NewBinarization(
|
||||
"RemIntra8x8PredMode",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
logger.Printf("TODO: ae for RemIntra8x8PredMode[%d]\n", luma8x8BlkIdx)
|
||||
|
@ -619,138 +620,138 @@ func MbPred(chromaArrayType int, sliceContext *SliceContext, br *bits.BitReader,
|
|||
}
|
||||
v = int(b)
|
||||
}
|
||||
if len(sliceContext.Slice.Data.RemIntra8x8PredMode) < luma8x8BlkIdx {
|
||||
sliceContext.Slice.Data.RemIntra8x8PredMode = append(
|
||||
sliceContext.Slice.Data.RemIntra8x8PredMode,
|
||||
make([]int, luma8x8BlkIdx-len(sliceContext.Slice.Data.RemIntra8x8PredMode)+1)...)
|
||||
if len(sliceContext.Slice.SliceData.RemIntra8x8PredMode) < luma8x8BlkIdx {
|
||||
sliceContext.Slice.SliceData.RemIntra8x8PredMode = append(
|
||||
sliceContext.Slice.SliceData.RemIntra8x8PredMode,
|
||||
make([]int, luma8x8BlkIdx-len(sliceContext.Slice.SliceData.RemIntra8x8PredMode)+1)...)
|
||||
}
|
||||
sliceContext.Slice.Data.RemIntra8x8PredMode[luma8x8BlkIdx] = v
|
||||
sliceContext.Slice.SliceData.RemIntra8x8PredMode[luma8x8BlkIdx] = v
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if chromaArrayType == 1 || chromaArrayType == 2 {
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: ue(v) or ae(v)
|
||||
binarization := NewBinarization(
|
||||
"IntraChromaPredMode",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
logger.Printf("TODO: ae for IntraChromaPredMode\n")
|
||||
} else {
|
||||
sliceContext.Slice.Data.IntraChromaPredMode = int(r.readUe())
|
||||
sliceContext.Slice.SliceData.IntraChromaPredMode = int(r.readUe())
|
||||
}
|
||||
}
|
||||
|
||||
} else if mbPartPredMode != direct {
|
||||
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ {
|
||||
sliceContext.Update(sliceContext.Slice.Header, sliceContext.Slice.Data)
|
||||
m, err := MbPartPredMode(sliceContext.Slice.Data, sliceType, sliceContext.Slice.Data.MbType, mbPartIdx)
|
||||
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, vid.SPS, sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData); mbPartIdx++ {
|
||||
sliceContext.Update(sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData)
|
||||
m, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceType, sliceContext.Slice.SliceData.MbType, mbPartIdx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("could not get mbPartPredMode for loop 1 mbPartIdx: %d", mbPartIdx))
|
||||
}
|
||||
if (sliceContext.Slice.Header.NumRefIdxL0ActiveMinus1 > 0 || sliceContext.Slice.Data.MbFieldDecodingFlag != sliceContext.Slice.Header.FieldPic) && m != predL1 {
|
||||
if (sliceContext.Slice.SliceHeader.NumRefIdxL0ActiveMinus1 > 0 || sliceContext.Slice.SliceData.MbFieldDecodingFlag != sliceContext.Slice.SliceHeader.FieldPic) && m != predL1 {
|
||||
logger.Printf("\tTODO: refIdxL0[%d] te or ae(v)\n", mbPartIdx)
|
||||
if len(sliceContext.Slice.Data.RefIdxL0) < mbPartIdx {
|
||||
sliceContext.Slice.Data.RefIdxL0 = append(
|
||||
sliceContext.Slice.Data.RefIdxL0, make([]int, mbPartIdx-len(sliceContext.Slice.Data.RefIdxL0)+1)...)
|
||||
if len(sliceContext.Slice.SliceData.RefIdxL0) < mbPartIdx {
|
||||
sliceContext.Slice.SliceData.RefIdxL0 = append(
|
||||
sliceContext.Slice.SliceData.RefIdxL0, make([]int, mbPartIdx-len(sliceContext.Slice.SliceData.RefIdxL0)+1)...)
|
||||
}
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: te(v) or ae(v)
|
||||
binarization := NewBinarization(
|
||||
"RefIdxL0",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
logger.Printf("TODO: ae for RefIdxL0[%d]\n", mbPartIdx)
|
||||
} else {
|
||||
// TODO: Only one reference picture is used for inter-prediction,
|
||||
// then the value should be 0
|
||||
if MbaffFrameFlag(sliceContext.SPS, sliceContext.Slice.Header) == 0 || !sliceContext.Slice.Data.MbFieldDecodingFlag {
|
||||
sliceContext.Slice.Data.RefIdxL0[mbPartIdx] = int(r.readTe(uint(sliceContext.Slice.Header.NumRefIdxL0ActiveMinus1)))
|
||||
if MbaffFrameFlag(vid.SPS, sliceContext.Slice.SliceHeader) == 0 || !sliceContext.Slice.SliceData.MbFieldDecodingFlag {
|
||||
sliceContext.Slice.SliceData.RefIdxL0[mbPartIdx] = int(r.readTe(uint(sliceContext.Slice.SliceHeader.NumRefIdxL0ActiveMinus1)))
|
||||
} else {
|
||||
rangeMax := 2*sliceContext.Slice.Header.NumRefIdxL0ActiveMinus1 + 1
|
||||
sliceContext.Slice.Data.RefIdxL0[mbPartIdx] = int(r.readTe(uint(rangeMax)))
|
||||
rangeMax := 2*sliceContext.Slice.SliceHeader.NumRefIdxL0ActiveMinus1 + 1
|
||||
sliceContext.Slice.SliceData.RefIdxL0[mbPartIdx] = int(r.readTe(uint(rangeMax)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ {
|
||||
m, err := MbPartPredMode(sliceContext.Slice.Data, sliceType, sliceContext.Slice.Data.MbType, mbPartIdx)
|
||||
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, vid.SPS, sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData); mbPartIdx++ {
|
||||
m, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceType, sliceContext.Slice.SliceData.MbType, mbPartIdx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("could not get mbPartPredMode for loop 2 mbPartIdx: %d", mbPartIdx))
|
||||
}
|
||||
if m != predL1 {
|
||||
for compIdx := 0; compIdx < 2; compIdx++ {
|
||||
if len(sliceContext.Slice.Data.MvdL0) < mbPartIdx {
|
||||
sliceContext.Slice.Data.MvdL0 = append(
|
||||
sliceContext.Slice.Data.MvdL0,
|
||||
make([][][]int, mbPartIdx-len(sliceContext.Slice.Data.MvdL0)+1)...)
|
||||
if len(sliceContext.Slice.SliceData.MvdL0) < mbPartIdx {
|
||||
sliceContext.Slice.SliceData.MvdL0 = append(
|
||||
sliceContext.Slice.SliceData.MvdL0,
|
||||
make([][][]int, mbPartIdx-len(sliceContext.Slice.SliceData.MvdL0)+1)...)
|
||||
}
|
||||
if len(sliceContext.Slice.Data.MvdL0[mbPartIdx][0]) < compIdx {
|
||||
sliceContext.Slice.Data.MvdL0[mbPartIdx][0] = append(
|
||||
sliceContext.Slice.Data.MvdL0[mbPartIdx][0],
|
||||
make([]int, compIdx-len(sliceContext.Slice.Data.MvdL0[mbPartIdx][0])+1)...)
|
||||
if len(sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0]) < compIdx {
|
||||
sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0] = append(
|
||||
sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0],
|
||||
make([]int, compIdx-len(sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0])+1)...)
|
||||
}
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: se(v) or ae(v)
|
||||
if compIdx == 0 {
|
||||
binarization := NewBinarization(
|
||||
"MvdLnEnd0",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
} else if compIdx == 1 {
|
||||
binarization := NewBinarization(
|
||||
"MvdLnEnd1",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
}
|
||||
logger.Printf("TODO: ae for MvdL0[%d][0][%d]\n", mbPartIdx, compIdx)
|
||||
} else {
|
||||
sliceContext.Slice.Data.MvdL0[mbPartIdx][0][compIdx], _ = readSe(br)
|
||||
sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0][compIdx], _ = readSe(br)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ {
|
||||
sliceContext.Update(sliceContext.Slice.Header, sliceContext.Slice.Data)
|
||||
m, err := MbPartPredMode(sliceContext.Slice.Data, sliceType, sliceContext.Slice.Data.MbType, mbPartIdx)
|
||||
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, vid.SPS, sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData); mbPartIdx++ {
|
||||
sliceContext.Update(sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData)
|
||||
m, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceType, sliceContext.Slice.SliceData.MbType, mbPartIdx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("could not get mbPartPredMode for loop 3 mbPartIdx: %d", mbPartIdx))
|
||||
}
|
||||
if m != predL0 {
|
||||
for compIdx := 0; compIdx < 2; compIdx++ {
|
||||
if len(sliceContext.Slice.Data.MvdL1) < mbPartIdx {
|
||||
sliceContext.Slice.Data.MvdL1 = append(
|
||||
sliceContext.Slice.Data.MvdL1,
|
||||
make([][][]int, mbPartIdx-len(sliceContext.Slice.Data.MvdL1)+1)...)
|
||||
if len(sliceContext.Slice.SliceData.MvdL1) < mbPartIdx {
|
||||
sliceContext.Slice.SliceData.MvdL1 = append(
|
||||
sliceContext.Slice.SliceData.MvdL1,
|
||||
make([][][]int, mbPartIdx-len(sliceContext.Slice.SliceData.MvdL1)+1)...)
|
||||
}
|
||||
if len(sliceContext.Slice.Data.MvdL1[mbPartIdx][0]) < compIdx {
|
||||
sliceContext.Slice.Data.MvdL1[mbPartIdx][0] = append(
|
||||
sliceContext.Slice.Data.MvdL0[mbPartIdx][0],
|
||||
make([]int, compIdx-len(sliceContext.Slice.Data.MvdL1[mbPartIdx][0])+1)...)
|
||||
if len(sliceContext.Slice.SliceData.MvdL1[mbPartIdx][0]) < compIdx {
|
||||
sliceContext.Slice.SliceData.MvdL1[mbPartIdx][0] = append(
|
||||
sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0],
|
||||
make([]int, compIdx-len(sliceContext.Slice.SliceData.MvdL1[mbPartIdx][0])+1)...)
|
||||
}
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
if compIdx == 0 {
|
||||
binarization := NewBinarization(
|
||||
"MvdLnEnd0",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
} else if compIdx == 1 {
|
||||
binarization := NewBinarization(
|
||||
"MvdLnEnd1",
|
||||
sliceContext.Slice.Data)
|
||||
sliceContext.Slice.SliceData)
|
||||
binarization.Decode(sliceContext, br, rbsp)
|
||||
|
||||
}
|
||||
// TODO: se(v) or ae(v)
|
||||
logger.Printf("TODO: ae for MvdL1[%d][0][%d]\n", mbPartIdx, compIdx)
|
||||
} else {
|
||||
sliceContext.Slice.Data.MvdL1[mbPartIdx][0][compIdx], _ = readSe(br)
|
||||
sliceContext.Slice.SliceData.MvdL1[mbPartIdx][0][compIdx], _ = readSe(br)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -873,47 +874,47 @@ func MbaffFrameFlag(sps *SPS, header *SliceHeader) int {
|
|||
return 0
|
||||
}
|
||||
|
||||
func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitReader) (*SliceData, error) {
|
||||
func NewSliceData(chromaArrayType int, vid *VideoStream, sliceContext *SliceContext, br *bits.BitReader) (*SliceData, error) {
|
||||
r := newFieldReader(br)
|
||||
var cabac *CABAC
|
||||
sliceContext.Slice.Data = &SliceData{BitReader: br}
|
||||
sliceContext.Slice.SliceData = &SliceData{BitReader: br}
|
||||
// TODO: Why is this being initialized here?
|
||||
// initCabac(sliceContext)
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
for !br.ByteAligned() {
|
||||
b, err := br.ReadBits(1)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read CabacAlignmentOneBit")
|
||||
}
|
||||
sliceContext.Slice.Data.CabacAlignmentOneBit = int(b)
|
||||
sliceContext.Slice.SliceData.CabacAlignmentOneBit = int(b)
|
||||
}
|
||||
}
|
||||
mbaffFrameFlag := 0
|
||||
if sliceContext.SPS.MBAdaptiveFrameFieldFlag && !sliceContext.Slice.Header.FieldPic {
|
||||
if vid.SPS.MBAdaptiveFrameFieldFlag && !sliceContext.Slice.SliceHeader.FieldPic {
|
||||
mbaffFrameFlag = 1
|
||||
}
|
||||
currMbAddr := sliceContext.Slice.Header.FirstMbInSlice * (1 * mbaffFrameFlag)
|
||||
currMbAddr := sliceContext.Slice.SliceHeader.FirstMbInSlice * (1 * mbaffFrameFlag)
|
||||
|
||||
moreDataFlag := true
|
||||
prevMbSkipped := 0
|
||||
sliceContext.Slice.Data.SliceTypeName = sliceTypeMap[sliceContext.Slice.Header.SliceType]
|
||||
sliceContext.Slice.Data.MbTypeName = MbTypeName(sliceContext.Slice.Data.SliceTypeName, sliceContext.Slice.Data.MbType)
|
||||
sliceContext.Slice.SliceData.SliceTypeName = sliceTypeMap[sliceContext.Slice.SliceHeader.SliceType]
|
||||
sliceContext.Slice.SliceData.MbTypeName = MbTypeName(sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType)
|
||||
logger.Printf("debug: \tSliceData: Processing moreData: %v\n", moreDataFlag)
|
||||
for moreDataFlag {
|
||||
logger.Printf("debug: \tLooking for more sliceContext.Slice.Data in slice type %s\n", sliceContext.Slice.Data.SliceTypeName)
|
||||
if sliceContext.Slice.Data.SliceTypeName != "I" && sliceContext.Slice.Data.SliceTypeName != "SI" {
|
||||
logger.Printf("debug: \tLooking for more sliceContext.Slice.SliceData in slice type %s\n", sliceContext.Slice.SliceData.SliceTypeName)
|
||||
if sliceContext.Slice.SliceData.SliceTypeName != "I" && sliceContext.Slice.SliceData.SliceTypeName != "SI" {
|
||||
logger.Printf("debug: \tNonI/SI slice, processing moreData\n")
|
||||
if sliceContext.PPS.EntropyCodingMode == 0 {
|
||||
sliceContext.Slice.Data.MbSkipRun = int(r.readUe())
|
||||
if vid.PPS.EntropyCodingMode == 0 {
|
||||
sliceContext.Slice.SliceData.MbSkipRun = int(r.readUe())
|
||||
|
||||
if sliceContext.Slice.Data.MbSkipRun > 0 {
|
||||
if sliceContext.Slice.SliceData.MbSkipRun > 0 {
|
||||
prevMbSkipped = 1
|
||||
}
|
||||
for i := 0; i < sliceContext.Slice.Data.MbSkipRun; i++ {
|
||||
for i := 0; i < sliceContext.Slice.SliceData.MbSkipRun; i++ {
|
||||
// nextMbAddress(currMbAdd
|
||||
currMbAddr = nextMbAddress(currMbAddr, sliceContext.SPS, sliceContext.PPS, sliceContext.Slice.Header)
|
||||
currMbAddr = nextMbAddress(currMbAddr, vid.SPS, vid.PPS, sliceContext.Slice.SliceHeader)
|
||||
}
|
||||
if sliceContext.Slice.Data.MbSkipRun > 0 {
|
||||
if sliceContext.Slice.SliceData.MbSkipRun > 0 {
|
||||
moreDataFlag = moreRBSPData(br)
|
||||
}
|
||||
} else {
|
||||
|
@ -921,16 +922,16 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read MbSkipFlag")
|
||||
}
|
||||
sliceContext.Slice.Data.MbSkipFlag = b == 1
|
||||
sliceContext.Slice.SliceData.MbSkipFlag = b == 1
|
||||
|
||||
moreDataFlag = !sliceContext.Slice.Data.MbSkipFlag
|
||||
moreDataFlag = !sliceContext.Slice.SliceData.MbSkipFlag
|
||||
}
|
||||
}
|
||||
if moreDataFlag {
|
||||
if mbaffFrameFlag == 1 && (currMbAddr%2 == 0 || (currMbAddr%2 == 1 && prevMbSkipped == 1)) {
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: ae implementation
|
||||
binarization := NewBinarization("MbFieldDecodingFlag", sliceContext.Slice.Data)
|
||||
binarization := NewBinarization("MbFieldDecodingFlag", sliceContext.Slice.SliceData)
|
||||
// TODO: this should take a BitReader where the nil is.
|
||||
binarization.Decode(sliceContext, br, nil)
|
||||
|
||||
|
@ -940,15 +941,15 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read MbFieldDecodingFlag")
|
||||
}
|
||||
sliceContext.Slice.Data.MbFieldDecodingFlag = b == 1
|
||||
sliceContext.Slice.SliceData.MbFieldDecodingFlag = b == 1
|
||||
}
|
||||
}
|
||||
|
||||
// BEGIN: macroblockLayer()
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
// TODO: ae implementation
|
||||
binarization := NewBinarization("MbType", sliceContext.Slice.Data)
|
||||
cabac = initCabac(binarization, sliceContext)
|
||||
binarization := NewBinarization("MbType", sliceContext.Slice.SliceData)
|
||||
cabac = initCabac(binarization, nil, sliceContext)
|
||||
_ = cabac
|
||||
// TODO: remove bytes parameter from this function.
|
||||
binarization.Decode(sliceContext, br, nil)
|
||||
|
@ -964,7 +965,7 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
if binarization.UseDecodeBypass == 1 {
|
||||
// DecodeBypass
|
||||
logger.Printf("TODO: decodeBypass is set: 9.3.3.2.3")
|
||||
codIRange, codIOffset, err := initDecodingEngine(sliceContext.Slice.Data.BitReader)
|
||||
codIRange, codIOffset, err := initDecodingEngine(sliceContext.Slice.SliceData.BitReader)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not initialise decoding engine")
|
||||
}
|
||||
|
@ -987,7 +988,7 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
}
|
||||
// Bypass decoding
|
||||
codIOffset, _, err = arithmeticDecoder.DecodeBypass(
|
||||
sliceContext.Slice.Data,
|
||||
sliceContext.Slice.SliceData,
|
||||
codIRange,
|
||||
codIOffset,
|
||||
)
|
||||
|
@ -1018,9 +1019,9 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
|
||||
logger.Printf("TODO: ae for MBType\n")
|
||||
} else {
|
||||
sliceContext.Slice.Data.MbType = int(r.readUe())
|
||||
sliceContext.Slice.SliceData.MbType = int(r.readUe())
|
||||
}
|
||||
if sliceContext.Slice.Data.MbTypeName == "I_PCM" {
|
||||
if sliceContext.Slice.SliceData.MbTypeName == "I_PCM" {
|
||||
for !br.ByteAligned() {
|
||||
_, err := br.ReadBits(1)
|
||||
if err != nil {
|
||||
|
@ -1028,35 +1029,35 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
}
|
||||
}
|
||||
// 7-3 p95
|
||||
bitDepthY := 8 + sliceContext.SPS.BitDepthLumaMinus8
|
||||
bitDepthY := 8 + vid.SPS.BitDepthLumaMinus8
|
||||
for i := 0; i < 256; i++ {
|
||||
s, err := br.ReadBits(int(bitDepthY))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("could not read PcmSampleLuma[%d]", i))
|
||||
}
|
||||
sliceContext.Slice.Data.PcmSampleLuma = append(
|
||||
sliceContext.Slice.Data.PcmSampleLuma,
|
||||
sliceContext.Slice.SliceData.PcmSampleLuma = append(
|
||||
sliceContext.Slice.SliceData.PcmSampleLuma,
|
||||
int(s))
|
||||
}
|
||||
// 9.3.1 p 246
|
||||
// cabac = initCabac(binarization, sliceContext)
|
||||
// 6-1 p 47
|
||||
mbWidthC := 16 / SubWidthC(sliceContext.SPS)
|
||||
mbHeightC := 16 / SubHeightC(sliceContext.SPS)
|
||||
mbWidthC := 16 / SubWidthC(vid.SPS)
|
||||
mbHeightC := 16 / SubHeightC(vid.SPS)
|
||||
// if monochrome
|
||||
if sliceContext.SPS.ChromaFormatIDC == chromaMonochrome || sliceContext.SPS.SeparateColorPlaneFlag {
|
||||
if vid.SPS.ChromaFormatIDC == chromaMonochrome || vid.SPS.SeparateColorPlaneFlag {
|
||||
mbWidthC = 0
|
||||
mbHeightC = 0
|
||||
}
|
||||
|
||||
bitDepthC := 8 + sliceContext.SPS.BitDepthChromaMinus8
|
||||
bitDepthC := 8 + vid.SPS.BitDepthChromaMinus8
|
||||
for i := 0; i < 2*mbWidthC*mbHeightC; i++ {
|
||||
s, err := br.ReadBits(int(bitDepthC))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("could not read PcmSampleChroma[%d]", i))
|
||||
}
|
||||
sliceContext.Slice.Data.PcmSampleChroma = append(
|
||||
sliceContext.Slice.Data.PcmSampleChroma,
|
||||
sliceContext.Slice.SliceData.PcmSampleChroma = append(
|
||||
sliceContext.Slice.SliceData.PcmSampleChroma,
|
||||
int(s))
|
||||
}
|
||||
// 9.3.1 p 246
|
||||
|
@ -1064,32 +1065,32 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
|
||||
} else {
|
||||
noSubMbPartSizeLessThan8x8Flag := 1
|
||||
m, err := MbPartPredMode(sliceContext.Slice.Data, sliceContext.Slice.Data.SliceTypeName, sliceContext.Slice.Data.MbType, 0)
|
||||
m, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType, 0)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get mbPartPredMode")
|
||||
}
|
||||
if sliceContext.Slice.Data.MbTypeName == "I_NxN" && m != intra16x16 && NumMbPart(sliceContext.NALUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data) == 4 {
|
||||
if sliceContext.Slice.SliceData.MbTypeName == "I_NxN" && m != intra16x16 && NumMbPart(sliceContext.NALUnit, vid.SPS, sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData) == 4 {
|
||||
logger.Printf("\tTODO: subMbPred\n")
|
||||
/*
|
||||
subMbType := SubMbPred(sliceContext.Slice.Data.MbType)
|
||||
subMbType := SubMbPred(sliceContext.Slice.SliceData.MbType)
|
||||
for mbPartIdx := 0; mbPartIdx < 4; mbPartIdx++ {
|
||||
if subMbType[mbPartIdx] != "B_Direct_8x8" {
|
||||
if NumbSubMbPart(subMbType[mbPartIdx]) > 1 {
|
||||
noSubMbPartSizeLessThan8x8Flag = 0
|
||||
}
|
||||
} else if !sliceContext.SPS.Direct8x8InferenceFlag {
|
||||
} else if !vid.SPS.Direct8x8InferenceFlag {
|
||||
noSubMbPartSizeLessThan8x8Flag = 0
|
||||
}
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
if sliceContext.PPS.Transform8x8Mode == 1 && sliceContext.Slice.Data.MbTypeName == "I_NxN" {
|
||||
if vid.PPS.Transform8x8Mode == 1 && sliceContext.Slice.SliceData.MbTypeName == "I_NxN" {
|
||||
// TODO
|
||||
// 1 bit or ae(v)
|
||||
// If sliceContext.PPS.EntropyCodingMode == 1, use ae(v)
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
binarization := NewBinarization("TransformSize8x8Flag", sliceContext.Slice.Data)
|
||||
cabac = initCabac(binarization, sliceContext)
|
||||
// If vid.PPS.EntropyCodingMode == 1, use ae(v)
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
binarization := NewBinarization("TransformSize8x8Flag", sliceContext.Slice.SliceData)
|
||||
cabac = initCabac(binarization, nil, sliceContext)
|
||||
binarization.Decode(sliceContext, br, nil)
|
||||
|
||||
logger.Println("TODO: ae(v) for TransformSize8x8Flag")
|
||||
|
@ -1098,22 +1099,22 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read TransformSize8x8Flag")
|
||||
}
|
||||
sliceContext.Slice.Data.TransformSize8x8Flag = b == 1
|
||||
sliceContext.Slice.SliceData.TransformSize8x8Flag = b == 1
|
||||
}
|
||||
}
|
||||
// TODO: fix nil argument for.
|
||||
MbPred(chromaArrayType, sliceContext, br, nil)
|
||||
MbPred(chromaArrayType, nil, sliceContext, br, nil)
|
||||
}
|
||||
m, err = MbPartPredMode(sliceContext.Slice.Data, sliceContext.Slice.Data.SliceTypeName, sliceContext.Slice.Data.MbType, 0)
|
||||
m, err = MbPartPredMode(sliceContext.Slice.SliceData, sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType, 0)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get mbPartPredMode")
|
||||
}
|
||||
if m != intra16x16 {
|
||||
// TODO: me, ae
|
||||
logger.Printf("TODO: CodedBlockPattern pending me/ae implementation\n")
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
binarization := NewBinarization("CodedBlockPattern", sliceContext.Slice.Data)
|
||||
cabac = initCabac(binarization, sliceContext)
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
binarization := NewBinarization("CodedBlockPattern", sliceContext.Slice.SliceData)
|
||||
cabac = initCabac(binarization, nil, sliceContext)
|
||||
// TODO: fix nil argument.
|
||||
binarization.Decode(sliceContext, br, nil)
|
||||
|
||||
|
@ -1123,17 +1124,17 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
br,
|
||||
uint(chromaArrayType),
|
||||
// TODO: fix this
|
||||
//MbPartPredMode(sliceContext.Slice.Data, sliceContext.Slice.Data.SliceTypeName, sliceContext.Slice.Data.MbType, 0)))
|
||||
//MbPartPredMode(sliceContext.Slice.SliceData, sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType, 0)))
|
||||
0)
|
||||
sliceContext.Slice.Data.CodedBlockPattern = int(me)
|
||||
sliceContext.Slice.SliceData.CodedBlockPattern = int(me)
|
||||
}
|
||||
|
||||
// sliceContext.Slice.Data.CodedBlockPattern = me(v) | ae(v)
|
||||
if CodedBlockPatternLuma(sliceContext.Slice.Data) > 0 && sliceContext.PPS.Transform8x8Mode == 1 && sliceContext.Slice.Data.MbTypeName != "I_NxN" && noSubMbPartSizeLessThan8x8Flag == 1 && (sliceContext.Slice.Data.MbTypeName != "B_Direct_16x16" || sliceContext.SPS.Direct8x8InferenceFlag) {
|
||||
// sliceContext.Slice.SliceData.CodedBlockPattern = me(v) | ae(v)
|
||||
if CodedBlockPatternLuma(sliceContext.Slice.SliceData) > 0 && vid.PPS.Transform8x8Mode == 1 && sliceContext.Slice.SliceData.MbTypeName != "I_NxN" && noSubMbPartSizeLessThan8x8Flag == 1 && (sliceContext.Slice.SliceData.MbTypeName != "B_Direct_16x16" || vid.SPS.Direct8x8InferenceFlag) {
|
||||
// TODO: 1 bit or ae(v)
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
binarization := NewBinarization("Transform8x8Flag", sliceContext.Slice.Data)
|
||||
cabac = initCabac(binarization, sliceContext)
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
binarization := NewBinarization("Transform8x8Flag", sliceContext.Slice.SliceData)
|
||||
cabac = initCabac(binarization, nil, sliceContext)
|
||||
// TODO: fix nil argument.
|
||||
binarization.Decode(sliceContext, br, nil)
|
||||
|
||||
|
@ -1143,36 +1144,36 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "coult not read TransformSize8x8Flag")
|
||||
}
|
||||
sliceContext.Slice.Data.TransformSize8x8Flag = b == 1
|
||||
sliceContext.Slice.SliceData.TransformSize8x8Flag = b == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
m, err = MbPartPredMode(sliceContext.Slice.Data, sliceContext.Slice.Data.SliceTypeName, sliceContext.Slice.Data.MbType, 0)
|
||||
m, err = MbPartPredMode(sliceContext.Slice.SliceData, sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType, 0)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get mbPartPredMode")
|
||||
}
|
||||
if CodedBlockPatternLuma(sliceContext.Slice.Data) > 0 || CodedBlockPatternChroma(sliceContext.Slice.Data) > 0 || m == intra16x16 {
|
||||
if CodedBlockPatternLuma(sliceContext.Slice.SliceData) > 0 || CodedBlockPatternChroma(sliceContext.Slice.SliceData) > 0 || m == intra16x16 {
|
||||
// TODO: se or ae(v)
|
||||
if sliceContext.PPS.EntropyCodingMode == 1 {
|
||||
binarization := NewBinarization("MbQpDelta", sliceContext.Slice.Data)
|
||||
cabac = initCabac(binarization, sliceContext)
|
||||
if vid.PPS.EntropyCodingMode == 1 {
|
||||
binarization := NewBinarization("MbQpDelta", sliceContext.Slice.SliceData)
|
||||
cabac = initCabac(binarization, nil, sliceContext)
|
||||
// TODO; fix nil argument
|
||||
binarization.Decode(sliceContext, br, nil)
|
||||
|
||||
logger.Printf("TODO: ae for MbQpDelta\n")
|
||||
} else {
|
||||
sliceContext.Slice.Data.MbQpDelta, _ = readSe(br)
|
||||
sliceContext.Slice.SliceData.MbQpDelta, _ = readSe(br)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} // END MacroblockLayer
|
||||
if sliceContext.PPS.EntropyCodingMode == 0 {
|
||||
if vid.PPS.EntropyCodingMode == 0 {
|
||||
moreDataFlag = moreRBSPData(br)
|
||||
} else {
|
||||
if sliceContext.Slice.Data.SliceTypeName != "I" && sliceContext.Slice.Data.SliceTypeName != "SI" {
|
||||
if sliceContext.Slice.Data.MbSkipFlag {
|
||||
if sliceContext.Slice.SliceData.SliceTypeName != "I" && sliceContext.Slice.SliceData.SliceTypeName != "SI" {
|
||||
if sliceContext.Slice.SliceData.MbSkipFlag {
|
||||
prevMbSkipped = 1
|
||||
} else {
|
||||
prevMbSkipped = 0
|
||||
|
@ -1186,17 +1187,17 @@ func NewSliceData(chromaArrayType int, sliceContext *SliceContext, br *bits.BitR
|
|||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read EndOfSliceFlag")
|
||||
}
|
||||
sliceContext.Slice.Data.EndOfSliceFlag = b == 1
|
||||
moreDataFlag = !sliceContext.Slice.Data.EndOfSliceFlag
|
||||
sliceContext.Slice.SliceData.EndOfSliceFlag = b == 1
|
||||
moreDataFlag = !sliceContext.Slice.SliceData.EndOfSliceFlag
|
||||
}
|
||||
}
|
||||
currMbAddr = nextMbAddress(currMbAddr, sliceContext.SPS, sliceContext.PPS, sliceContext.Slice.Header)
|
||||
currMbAddr = nextMbAddress(currMbAddr, vid.SPS, vid.PPS, sliceContext.Slice.SliceHeader)
|
||||
} // END while moreDataFlag
|
||||
return sliceContext.Slice.Data, nil
|
||||
return sliceContext.Slice.SliceData, nil
|
||||
}
|
||||
|
||||
func (c *SliceContext) Update(header *SliceHeader, data *SliceData) {
|
||||
c.Slice = &Slice{Header: header, Data: data}
|
||||
c.Slice = &Slice{SliceHeader: header, SliceData: data}
|
||||
}
|
||||
func NewSliceContext(vid *VideoStream, nalUnit *NALUnit, rbsp []byte, showPacket bool) (*SliceContext, error) {
|
||||
var err error
|
||||
|
@ -1360,13 +1361,11 @@ func NewSliceContext(vid *VideoStream, nalUnit *NALUnit, rbsp []byte, showPacket
|
|||
|
||||
sliceContext := &SliceContext{
|
||||
NALUnit: nalUnit,
|
||||
SPS: sps,
|
||||
PPS: pps,
|
||||
Slice: &Slice{
|
||||
Header: &header,
|
||||
SliceHeader: &header,
|
||||
},
|
||||
}
|
||||
sliceContext.Slice.Data, err = NewSliceData(vid.ChromaArrayType, sliceContext, br)
|
||||
sliceContext.Slice.SliceData, err = NewSliceData(vid.ChromaArrayType, nil, sliceContext, br)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not create slice data")
|
||||
}
|
||||
|
|
|
@ -26,34 +26,43 @@ LICENSE
|
|||
|
||||
package h264
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"bitbucket.org/ausocean/av/codec/h264/h264dec"
|
||||
)
|
||||
|
||||
var errNotEnoughBytes = errors.New("not enough bytes to read")
|
||||
|
||||
// NALType returns the NAL type of the given NAL unit bytes. The given NAL unit
|
||||
// may be in byte stream or packet format.
|
||||
// NB: access unit delimiters are skipped.
|
||||
func NALType(n []byte) (int, error) {
|
||||
sc := frameScanner{buf: n}
|
||||
b, ok := sc.readByte()
|
||||
if !ok {
|
||||
return 0, errNotEnoughBytes
|
||||
}
|
||||
for i := 1; b == 0x00 && i != 4; i++ {
|
||||
b, ok = sc.readByte()
|
||||
for {
|
||||
b, ok := sc.readByte()
|
||||
if !ok {
|
||||
return 0, errNotEnoughBytes
|
||||
}
|
||||
if b != 0x01 || (i != 2 && i != 3) {
|
||||
continue
|
||||
}
|
||||
for i := 1; b == 0x00 && i != 4; i++ {
|
||||
b, ok = sc.readByte()
|
||||
if !ok {
|
||||
return 0, errNotEnoughBytes
|
||||
}
|
||||
if b != 0x01 || (i != 2 && i != 3) {
|
||||
continue
|
||||
}
|
||||
|
||||
b, ok = sc.readByte()
|
||||
if !ok {
|
||||
return 0, errNotEnoughBytes
|
||||
b, ok = sc.readByte()
|
||||
if !ok {
|
||||
return 0, errNotEnoughBytes
|
||||
}
|
||||
nalType := int(b & 0x1f)
|
||||
if nalType != h264dec.NALTypeAccessUnitDelimiter {
|
||||
return nalType, nil
|
||||
}
|
||||
}
|
||||
return int(b & 0x1f), nil
|
||||
}
|
||||
return int(b & 0x1f), nil
|
||||
}
|
||||
|
||||
type frameScanner struct {
|
||||
|
|
|
@ -44,7 +44,7 @@ import (
|
|||
const (
|
||||
H264ID = 27
|
||||
H265ID = 36
|
||||
audioStreamID = 0xc0 // First audio stream ID.
|
||||
audioStreamID = 0xc0 // ADPCM audio stream ID.
|
||||
)
|
||||
|
||||
// Constants used to communicate which media codec will be packetized.
|
||||
|
@ -150,10 +150,12 @@ type Encoder struct {
|
|||
func NewEncoder(dst io.WriteCloser, rate float64, mediaType int) *Encoder {
|
||||
var mPid int
|
||||
var sid byte
|
||||
nbp := true
|
||||
switch mediaType {
|
||||
case EncodeAudio:
|
||||
mPid = AudioPid
|
||||
sid = audioStreamID
|
||||
nbp = false
|
||||
case EncodeH265:
|
||||
mPid = VideoPid
|
||||
sid = H265ID
|
||||
|
@ -168,7 +170,7 @@ func NewEncoder(dst io.WriteCloser, rate float64, mediaType int) *Encoder {
|
|||
Pil: 0,
|
||||
Essd: &psi.ESSD{
|
||||
St: byte(sid),
|
||||
Epid: 0x0100,
|
||||
Epid: uint16(mPid),
|
||||
Esil: 0x00,
|
||||
},
|
||||
}
|
||||
|
@ -180,7 +182,7 @@ func NewEncoder(dst io.WriteCloser, rate float64, mediaType int) *Encoder {
|
|||
writePeriod: time.Duration(float64(time.Second) / rate),
|
||||
ptsOffset: ptsOffset,
|
||||
|
||||
nalBasedPSI: true,
|
||||
nalBasedPSI: nbp,
|
||||
|
||||
pktCount: 8,
|
||||
|
||||
|
|
|
@ -101,7 +101,10 @@ func TestEncodeVideo(t *testing.T) {
|
|||
|
||||
// Create the dst and write the test data to encoder.
|
||||
dst := &destination{}
|
||||
_, err := NewEncoder(nopCloser{dst}, 25, EncodeH264).Write(data)
|
||||
e := NewEncoder(nopCloser{dst}, 25, EncodeH264)
|
||||
e.NALBasedPSI(false, psiSendCount)
|
||||
|
||||
_, err := e.Write(data)
|
||||
if err != nil {
|
||||
t.Fatalf("could not write data to encoder, failed with err: %v\n", err)
|
||||
}
|
||||
|
|
6
go.mod
6
go.mod
|
@ -3,12 +3,14 @@ module bitbucket.org/ausocean/av
|
|||
go 1.12
|
||||
|
||||
require (
|
||||
bitbucket.org/ausocean/iot v1.2.6
|
||||
bitbucket.org/ausocean/utils v1.2.8
|
||||
bitbucket.org/ausocean/iot v1.2.7
|
||||
bitbucket.org/ausocean/utils v1.2.9
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/Comcast/gots v0.0.0-20190305015453-8d56e473f0f7
|
||||
github.com/go-audio/audio v0.0.0-20181013203223-7b2a6ca21480
|
||||
github.com/go-audio/wav v0.0.0-20181013172942-de841e69b884
|
||||
github.com/mewkiz/flac v1.0.5
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/yobert/alsa v0.0.0-20180630182551-d38d89fa843e
|
||||
gopkg.in/yaml.v2 v2.2.2 // indirect
|
||||
)
|
||||
|
|
14
go.sum
14
go.sum
|
@ -1,16 +1,15 @@
|
|||
bitbucket.org/ausocean/av v0.0.0-20190416003121-6ee286e98874/go.mod h1:DxZEprrNNQ2slHKAQVUHryDaWc5CbjxyHAvomhzg+AE=
|
||||
bitbucket.org/ausocean/iot v1.2.4 h1:M/473iQ0d4q+76heerjAQuqXzQyc5dZ3F7Bfuq6X7q4=
|
||||
bitbucket.org/ausocean/iot v1.2.4/go.mod h1:5HVLgPHccW2PxS7WDUQO6sKWMgk3Vfze/7d5bHs8EWU=
|
||||
bitbucket.org/ausocean/iot v1.2.5 h1:udD5X4oXUuKwdjO7bcq4StcDdjP8fJa2L0FnJJwF+6Q=
|
||||
bitbucket.org/ausocean/iot v1.2.5/go.mod h1:dOclxXkdxAQGWO7Y5KcP1wpNfxg9oKUA2VqjJ3Le4RA=
|
||||
bitbucket.org/ausocean/iot v1.2.6 h1:KAAY1KZDbyOpoKajT1dM8BawupHiW9hUOelseSV1Ptc=
|
||||
bitbucket.org/ausocean/iot v1.2.6/go.mod h1:71AYHh8yGZ8XyzDBskwIWMF+8E8ORagXpXE24wlhoE0=
|
||||
bitbucket.org/ausocean/iot v1.2.7 h1:dZgrmVtuXnzHgybDthn0bYgAJms9euTONXBsqsx9g5M=
|
||||
bitbucket.org/ausocean/iot v1.2.7/go.mod h1:aAWgPo2f8sD2OPmxae1E5/iD9+tKY/iW4pcQMQXUvHM=
|
||||
bitbucket.org/ausocean/utils v0.0.0-20190408050157-66d3b4d4041e/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8=
|
||||
bitbucket.org/ausocean/utils v1.2.4/go.mod h1:5JIXFTAMMNl5Ob79tpZfDCJ+gOO8rj7v4ORj56tHZpw=
|
||||
bitbucket.org/ausocean/utils v1.2.6 h1:JN66APCV+hu6GebIHSu2KSywhLym4vigjSz5+fB0zXc=
|
||||
bitbucket.org/ausocean/utils v1.2.6/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8=
|
||||
bitbucket.org/ausocean/utils v1.2.8 h1:wRlajOtaMz/loUrGmFf4SUcTnZALtTqgPmk49iHMWxs=
|
||||
bitbucket.org/ausocean/utils v1.2.8 h1:hyxAIqYBqjqCguG+6A/kKyrAihyeUt2LziZg6CH0gLU=
|
||||
bitbucket.org/ausocean/utils v1.2.8/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8=
|
||||
bitbucket.org/ausocean/utils v1.2.9 h1:g45C6KCNvCLOGFv+ZnmDbQOOdnwpIsvzuNOD141CTVI=
|
||||
bitbucket.org/ausocean/utils v1.2.9/go.mod h1:uXzX9z3PLemyURTMWRhVI8uLhPX4uuvaaO85v2hcob8=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Comcast/gots v0.0.0-20190305015453-8d56e473f0f7 h1:LdOc9B9Bj6LEsKiXShkLA3/kpxXb6LJpH+ekU2krbzw=
|
||||
|
@ -20,8 +19,8 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx
|
|||
github.com/adrianmo/go-nmea v1.1.1-0.20190109062325-c448653979f7/go.mod h1:HHPxPAm2kmev+61qmkZh7xgZF/7qHtSpsWppip2Ipv8=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-audio/aiff v0.0.0-20180403003018-6c3a8a6aff12/go.mod h1:AMSAp6W1zd0koOdX6QDgGIuBDTUvLa2SLQtm7d9eM3c=
|
||||
github.com/go-audio/audio v0.0.0-20180206231410-b697a35b5608/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
|
||||
|
@ -53,7 +52,6 @@ go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
|
|||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
|
|
|
@ -119,10 +119,11 @@ type Revid struct {
|
|||
// an error if construction of the new instance was not successful.
|
||||
func New(c Config, ns *netsender.Sender) (*Revid, error) {
|
||||
r := Revid{ns: ns, err: make(chan error)}
|
||||
err := r.reset(c)
|
||||
err := r.setConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("could not set config, failed with error: %v",err)
|
||||
}
|
||||
r.config.Logger.SetLevel(c.LogLevel)
|
||||
go r.handleErrors()
|
||||
return &r, nil
|
||||
}
|
||||
|
@ -317,12 +318,17 @@ func (r *Revid) Start() error {
|
|||
}
|
||||
r.config.Logger.Log(logger.Info, pkg+"starting Revid")
|
||||
r.isRunning = true
|
||||
var err error
|
||||
err := r.reset(r.config)
|
||||
if err != nil {
|
||||
r.Stop()
|
||||
return err
|
||||
}
|
||||
r.closeInput, err = r.setupInput()
|
||||
if err != nil {
|
||||
r.Stop()
|
||||
return err
|
||||
}
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop closes down the pipeline. This closes encoders and sender output routines,
|
||||
|
@ -543,7 +549,7 @@ func (r *Revid) Update(vars map[string]string) error {
|
|||
}
|
||||
}
|
||||
r.config.Logger.Log(logger.Info, pkg+"revid config changed", "config", fmt.Sprintf("%+v", r.config))
|
||||
return r.reset(r.config)
|
||||
return nil
|
||||
}
|
||||
|
||||
// startRaspivid sets up things for input from raspivid i.e. starts
|
||||
|
|
Loading…
Reference in New Issue