├── .github └── workflows │ └── test.yml ├── LICENSE ├── README.md ├── audio.go ├── buffer.go ├── demux.go ├── go.mod ├── mpeg.go ├── mpeg_test.go ├── testdata ├── test.mp2 ├── test.mpeg1video └── test.mpg └── video.go /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: Test 3 | jobs: 4 | test: 5 | strategy: 6 | matrix: 7 | go-version: [1.19.x] 8 | os: [ubuntu-latest] 9 | runs-on: ${{ matrix.os }} 10 | steps: 11 | - name: Install Go 12 | uses: actions/setup-go@v3 13 | with: 14 | go-version: ${{ matrix.go-version }} 15 | - name: Checkout code 16 | uses: actions/checkout@v3 17 | - name: Test 18 | run: go test 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2022, Milan Nikolic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## mpeg 2 | [![Status](https://github.com/gen2brain/mpeg/actions/workflows/test.yml/badge.svg)](https://github.com/gen2brain/mpeg/actions) 3 | [![Go Reference](https://pkg.go.dev/badge/github.com/gen2brain/mpeg.svg)](https://pkg.go.dev/github.com/gen2brain/mpeg) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/gen2brain/mpeg?branch=main)](https://goreportcard.com/report/github.com/gen2brain/mpeg) 5 | 6 | `MPEG-1` Video decoder, `MP2` Audio decoder and `MPEG-PS` Demuxer in pure Go. 7 | 8 | ### Why 9 | 10 | This is a simple way to get video playback into your app or game. 11 | 12 | `MPEG-1` is an old and inefficient codec, but it is still good enough for many use cases. The quality and compression ratio still holds up surprisingly well. 13 | Decoding costs very little CPU time compared to modern video formats. All patents related to `MPEG-1` and `MP2` have expired, so it is entirely free now. 14 | 15 | ### Examples 16 | 17 | - [frames](https://github.com/gen2brain/mpeg-examples/blob/main/frames) - extracts all frames from a video and saves them as JPEG 18 | - [player-eb](https://github.com/gen2brain/mpeg-examples/blob/main/player-eb) - player using `Ebitengine`, also check better, [accelerated example](https://github.com/hajimehoshi/ebiten/tree/main/examples/video) 19 | - [player-rl](https://github.com/gen2brain/mpeg-examples/blob/main/player-rl) - player using `raylib` with YUV->RGB conversion done on CPU 20 | - [player-sdl](https://github.com/gen2brain/mpeg-examples/blob/main/player-sdl) - player using `SDL2` with accelerated YUV->RGB conversion 21 | - [player-web](https://github.com/gen2brain/mpeg-examples/blob/main/player-web) - player using `WebGL` and `WebAudio`, see [live example](https://gen2brain.github.io/mpeg) 22 | - [player-xv](https://github.com/gen2brain/mpeg-examples/blob/main/player-xv) - player using `X11/XVideo` and `OSS`, accelerated 23 | 24 | ### Format 25 | 26 | Most [MPEG-PS](https://en.wikipedia.org/wiki/MPEG_program_stream) (`.mpg`) files containing [MPEG-1](https://en.wikipedia.org/wiki/MPEG-1) video (`mpeg1video`) and [MPEG-1 Audio Layer II](https://en.wikipedia.org/wiki/MPEG-1_Audio_Layer_II) (`mp2`) streams should work. 27 | 28 | Note that `.mpg` files can also contain [MPEG-2](https://en.wikipedia.org/wiki/MPEG-2) video, which this library does not support. 29 | 30 | You can encode video in a suitable format with `FFmpeg`: 31 | ``` 32 | ffmpeg -i input.mp4 -c:v mpeg1video -q:v 0 -c:a mp2 -format mpeg output.mpg 33 | ``` 34 | 35 | `-q:v` sets a fixed video quality with a variable bitrate, where `0` is the highest. 36 | You can use `-b:v` to set a fixed bitrate instead; e.g. `-b:v 2000k` for 2000 kbit/s. 37 | Refer to the [FFmpeg documentation](https://ffmpeg.org/ffmpeg.html#Options) for more details. 38 | 39 | ### Credits 40 | 41 | * [pl_mpeg](https://github.com/phoboslab/pl_mpeg) by Dominic Szablewski. 42 | * [javampeg1video](https://sourceforge.net/projects/javampeg1video/) by Korandi Zoltan. 43 | * [kjmp2](https://keyj.emphy.de/kjmp2/) by Martin J. Fiedler. 44 | -------------------------------------------------------------------------------- /audio.go: -------------------------------------------------------------------------------- 1 | package mpeg 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "unsafe" 7 | ) 8 | 9 | const ( 10 | // SamplesPerFrame is the default count of samples. 11 | SamplesPerFrame = 1152 12 | ) 13 | 14 | type AudioFormat int 15 | 16 | const ( 17 | // AudioF32N - 32-bit floating point samples, normalized 18 | AudioF32N AudioFormat = iota 19 | // AudioF32NLR - 32-bit floating point samples, normalized, separate channels 20 | AudioF32NLR 21 | // AudioF32 - 32-bit floating point samples 22 | AudioF32 23 | // AudioS16 - signed 16-bit samples 24 | AudioS16 25 | ) 26 | 27 | // Samples represents decoded audio samples, stored as normalized (-1, 1) float32, 28 | // interleaved and in separate channels. 29 | type Samples struct { 30 | Time float64 31 | S16 []int16 32 | F32 []float32 33 | Left []float32 34 | Right []float32 35 | Interleaved []float32 36 | 37 | format AudioFormat 38 | } 39 | 40 | // Bytes returns interleaved samples as slice of bytes. 41 | func (s *Samples) Bytes() []byte { 42 | switch s.format { 43 | case AudioF32N: 44 | return unsafe.Slice((*byte)(unsafe.Pointer(&s.Interleaved[0])), len(s.Interleaved)*4) 45 | case AudioF32: 46 | return unsafe.Slice((*byte)(unsafe.Pointer(&s.F32[0])), len(s.F32)*4) 47 | case AudioS16: 48 | return unsafe.Slice((*byte)(unsafe.Pointer(&s.S16[0])), len(s.S16)*2) 49 | } 50 | 51 | return nil 52 | } 53 | 54 | type SamplesReader struct { 55 | reader *bytes.Reader 56 | } 57 | 58 | // Read implements the io.Reader interface. 59 | func (s *SamplesReader) Read(b []byte) (int, error) { 60 | if s.reader.Len() == 0 { 61 | _, err := s.reader.Seek(0, io.SeekStart) 62 | if err != nil { 63 | return 0, err 64 | } 65 | } 66 | 67 | return s.reader.Read(b) 68 | } 69 | 70 | // Seek implements the io.Seeker interface. 71 | func (s *SamplesReader) Seek(offset int64, whence int) (int64, error) { 72 | return 0, nil 73 | } 74 | 75 | // Audio decodes MPEG-1 Audio Layer II (mp2) data into raw samples. 76 | type Audio struct { 77 | time float64 78 | samplesDecoded int 79 | samplerateIndex int 80 | bitrateIndex int 81 | version int 82 | layer int 83 | mode int 84 | channels int 85 | bound int 86 | vPos int 87 | nextFrameDataSize int 88 | hasHeader bool 89 | 90 | buf *Buffer 91 | 92 | allocation [2][32]*quantizerSpec 93 | scaleFactorInfo [2][32]byte 94 | scaleFactor [2][32][3]int 95 | sample [2][32][3]int 96 | 97 | samples Samples 98 | format AudioFormat 99 | 100 | d []float32 101 | v [][]float32 102 | u []float32 103 | } 104 | 105 | // NewAudio creates an audio decoder with buffer as a source. 106 | func NewAudio(buf *Buffer) *Audio { 107 | audio := &Audio{} 108 | 109 | audio.buf = buf 110 | audio.samplerateIndex = 3 // Indicates 0 111 | 112 | audio.samples.S16 = make([]int16, SamplesPerFrame*2) 113 | audio.samples.F32 = make([]float32, SamplesPerFrame*2) 114 | audio.samples.Left = make([]float32, SamplesPerFrame) 115 | audio.samples.Right = make([]float32, SamplesPerFrame) 116 | audio.samples.Interleaved = make([]float32, SamplesPerFrame*2) 117 | 118 | audio.d = make([]float32, 1024) 119 | for i, d := range synthesisWindow { 120 | audio.d[i] = d 121 | audio.d[i+512] = d 122 | } 123 | 124 | audio.v = make([][]float32, 2) 125 | for i := range audio.v { 126 | audio.v[i] = make([]float32, 1024) 127 | } 128 | 129 | audio.u = make([]float32, 32) 130 | 131 | // Attempt to decode first header 132 | audio.nextFrameDataSize = audio.decodeHeader() 133 | 134 | return audio 135 | } 136 | 137 | // Reader returns samples reader. 138 | func (a *Audio) Reader() io.Reader { 139 | switch a.format { 140 | case AudioF32N: 141 | b := unsafe.Slice((*byte)(unsafe.Pointer(&a.samples.Interleaved[0])), len(a.samples.Interleaved)*4) 142 | return &SamplesReader{bytes.NewReader(b)} 143 | case AudioF32: 144 | b := unsafe.Slice((*byte)(unsafe.Pointer(&a.samples.F32[0])), len(a.samples.F32)*4) 145 | return &SamplesReader{bytes.NewReader(b)} 146 | case AudioS16: 147 | b := unsafe.Slice((*byte)(unsafe.Pointer(&a.samples.S16[0])), len(a.samples.S16)*2) 148 | return &SamplesReader{bytes.NewReader(b)} 149 | } 150 | 151 | return nil 152 | } 153 | 154 | // Buffer returns audio buffer. 155 | func (a *Audio) Buffer() *Buffer { 156 | return a.buf 157 | } 158 | 159 | // HasHeader checks whether a frame header was found, and we can accurately report on samplerate. 160 | func (a *Audio) HasHeader() bool { 161 | if a.hasHeader { 162 | return true 163 | } 164 | 165 | a.nextFrameDataSize = a.decodeHeader() 166 | 167 | return a.hasHeader 168 | } 169 | 170 | // Samplerate returns the sample rate in samples per second. 171 | func (a *Audio) Samplerate() int { 172 | if a.HasHeader() { 173 | return int(samplerate[a.samplerateIndex]) 174 | } 175 | 176 | return 0 177 | } 178 | 179 | // Channels returns the number of channels. 180 | func (a *Audio) Channels() int { 181 | return a.channels 182 | } 183 | 184 | // Time returns the current internal time in seconds. 185 | func (a *Audio) Time() float64 { 186 | return a.time 187 | } 188 | 189 | // SetTime sets the current internal time in seconds. This is only useful when you 190 | // manipulate the underlying video buffer and want to enforce a correct timestamps. 191 | func (a *Audio) SetTime(time float64) { 192 | a.samplesDecoded = int(time * float64(samplerate[a.samplerateIndex])) 193 | a.time = time 194 | } 195 | 196 | // Rewind rewinds the internal buffer. 197 | func (a *Audio) Rewind() { 198 | a.buf.Rewind() 199 | a.time = 0 200 | a.samplesDecoded = 0 201 | a.nextFrameDataSize = 0 202 | } 203 | 204 | // HasEnded checks whether the file has ended. This will be cleared on rewind. 205 | func (a *Audio) HasEnded() bool { 206 | return a.buf.HasEnded() 207 | } 208 | 209 | // Decode decodes and returns one "frame" of audio and advance the 210 | // internal time by (SamplesPerFrame/samplerate) seconds. 211 | func (a *Audio) Decode() *Samples { 212 | // Do we have at least enough information to decode the frame header? 213 | if a.nextFrameDataSize == 0 { 214 | a.nextFrameDataSize = a.decodeHeader() 215 | } 216 | 217 | if a.nextFrameDataSize == 0 || !a.buf.has(a.nextFrameDataSize<<3) { 218 | return nil 219 | } 220 | 221 | a.decodeFrame() 222 | a.nextFrameDataSize = 0 223 | 224 | a.samples.Time = a.time 225 | 226 | a.samplesDecoded += SamplesPerFrame 227 | a.time = float64(a.samplesDecoded) / float64(samplerate[a.samplerateIndex]) 228 | 229 | return &a.samples 230 | } 231 | 232 | func (a *Audio) decodeHeader() int { 233 | if !a.buf.has(48) { 234 | return 0 235 | } 236 | 237 | a.buf.skipBytes(0x00) 238 | sync := a.buf.read(11) 239 | 240 | // Attempt to resync if no syncword was found. This sucks balls. The MP2 241 | // stream contains a syncword just before every frame (11 bits set to 1). 242 | // However, this syncword is not guaranteed to not occur elsewhere in the 243 | // stream. So, if we have to resync, we also have to check if the header 244 | // (samplerate, bitrate) differs from the one we had before. This all 245 | // may still lead to garbage data being decoded :/ 246 | 247 | if sync != frameSync && !a.buf.findFrameSync() { 248 | return 0 249 | } 250 | 251 | a.version = a.buf.read(2) 252 | a.layer = a.buf.read(2) 253 | hasCRC := a.buf.read1() == 0 254 | 255 | if a.version != mpeg1 || a.layer != layerII { 256 | return 0 257 | } 258 | 259 | bitrateIndex := a.buf.read(4) - 1 260 | if bitrateIndex > 13 { 261 | return 0 262 | } 263 | 264 | samplerateIndex := a.buf.read(2) 265 | if samplerateIndex == 3 { 266 | return 0 267 | } 268 | 269 | padding := a.buf.read1() 270 | a.buf.skip(1) // f_private 271 | mode := a.buf.read(2) 272 | 273 | // If we already have a header, make sure the samplerate, bitrate and mode 274 | // are still the same, otherwise we might have missed sync. 275 | 276 | if a.hasHeader && (a.bitrateIndex != bitrateIndex || a.samplerateIndex != samplerateIndex || a.mode != mode) { 277 | return 0 278 | } 279 | 280 | a.bitrateIndex = bitrateIndex 281 | a.samplerateIndex = samplerateIndex 282 | a.mode = mode 283 | a.hasHeader = true 284 | 285 | if mode == modeStereo || mode == modeJointStereo { 286 | a.channels = 2 287 | } else if mode == modeMono { 288 | a.channels = 1 289 | } 290 | 291 | // Parse the mode_extension, set up the stereo bound 292 | if mode == modeJointStereo { 293 | a.bound = (a.buf.read(2) + 1) << 2 294 | } else { 295 | a.buf.skip(2) 296 | if mode == modeMono { 297 | a.bound = 0 298 | } else { 299 | a.bound = 32 300 | } 301 | } 302 | 303 | // Discard the last 4 bits of the header and the CRC Value, if present 304 | a.buf.skip(4) // copyright(1), original(1), emphasis(2) 305 | if hasCRC { 306 | a.buf.skip(16) 307 | } 308 | 309 | // Compute frame size, check if we have enough data to decode the whole frame. 310 | br := bitrate[a.bitrateIndex] 311 | sr := samplerate[a.samplerateIndex] 312 | frameSize := (144000 * int(br) / int(sr)) + padding 313 | 314 | r := 4 315 | if hasCRC { 316 | r = 6 317 | } 318 | 319 | return frameSize - r 320 | } 321 | 322 | func (a *Audio) decodeFrame() { 323 | // Prepare the quantizer table lookups 324 | tab1 := 1 325 | if a.mode == modeMono { 326 | tab1 = 0 327 | } 328 | tab2 := int(quantLutStep1[tab1][a.bitrateIndex]) 329 | tab3 := int(quantLutStep2[tab2][a.samplerateIndex]) 330 | 331 | sblimit := tab3 & 63 332 | tab3 >>= 6 333 | 334 | if a.bound > sblimit { 335 | a.bound = sblimit 336 | } 337 | 338 | // read the allocation information 339 | for sb := 0; sb < a.bound; sb++ { 340 | a.allocation[0][sb] = a.readAllocation(sb, tab3) 341 | a.allocation[1][sb] = a.readAllocation(sb, tab3) 342 | } 343 | 344 | for sb := a.bound; sb < sblimit; sb++ { 345 | a.allocation[0][sb] = a.readAllocation(sb, tab3) 346 | a.allocation[1][sb] = a.allocation[0][sb] 347 | } 348 | 349 | // read scale factor selector information 350 | channels := 2 351 | if a.mode == modeMono { 352 | channels = 1 353 | } 354 | 355 | for sb := 0; sb < sblimit; sb++ { 356 | for ch := 0; ch < channels; ch++ { 357 | if a.allocation[ch][sb] != nil { 358 | a.scaleFactorInfo[ch][sb] = byte(a.buf.read(2)) 359 | } 360 | } 361 | if a.mode == modeMono { 362 | a.scaleFactorInfo[1][sb] = a.scaleFactorInfo[0][sb] 363 | } 364 | } 365 | 366 | // read scale factors 367 | for sb := 0; sb < sblimit; sb++ { 368 | for ch := 0; ch < channels; ch++ { 369 | if a.allocation[ch][sb] != nil { 370 | switch a.scaleFactorInfo[ch][sb] { 371 | case 0: 372 | a.scaleFactor[ch][sb][0] = a.buf.read(6) 373 | a.scaleFactor[ch][sb][1] = a.buf.read(6) 374 | a.scaleFactor[ch][sb][2] = a.buf.read(6) 375 | case 1: 376 | tmp := a.buf.read(6) 377 | a.scaleFactor[ch][sb][0] = tmp 378 | a.scaleFactor[ch][sb][1] = tmp 379 | a.scaleFactor[ch][sb][2] = a.buf.read(6) 380 | case 2: 381 | tmp := a.buf.read(6) 382 | a.scaleFactor[ch][sb][0] = tmp 383 | a.scaleFactor[ch][sb][1] = tmp 384 | a.scaleFactor[ch][sb][2] = tmp 385 | case 3: 386 | a.scaleFactor[ch][sb][0] = a.buf.read(6) 387 | tmp := a.buf.read(6) 388 | a.scaleFactor[ch][sb][1] = tmp 389 | a.scaleFactor[ch][sb][2] = tmp 390 | } 391 | } 392 | } 393 | 394 | if a.mode == modeMono { 395 | a.scaleFactor[1][sb][0] = a.scaleFactor[0][sb][0] 396 | a.scaleFactor[1][sb][1] = a.scaleFactor[0][sb][1] 397 | a.scaleFactor[1][sb][2] = a.scaleFactor[0][sb][2] 398 | } 399 | } 400 | 401 | // Coefficient input and reconstruction 402 | outPos := 0 403 | for part := 0; part < 3; part++ { 404 | for granule := 0; granule < 4; granule++ { 405 | // Read the samples 406 | for sb := 0; sb < a.bound; sb++ { 407 | a.readSamples(0, sb, part) 408 | a.readSamples(1, sb, part) 409 | } 410 | for sb := a.bound; sb < sblimit; sb++ { 411 | a.readSamples(0, sb, part) 412 | a.sample[1][sb][0] = a.sample[0][sb][0] 413 | a.sample[1][sb][1] = a.sample[0][sb][1] 414 | a.sample[1][sb][2] = a.sample[0][sb][2] 415 | } 416 | for sb := sblimit; sb < 32; sb++ { 417 | a.sample[0][sb][0] = 0 418 | a.sample[0][sb][1] = 0 419 | a.sample[0][sb][2] = 0 420 | a.sample[1][sb][0] = 0 421 | a.sample[1][sb][1] = 0 422 | a.sample[1][sb][2] = 0 423 | } 424 | 425 | // Synthesis loop 426 | for p := 0; p < 3; p++ { 427 | // Shifting step 428 | a.vPos = (a.vPos - 64) & 1023 429 | 430 | for ch := 0; ch < 2; ch++ { 431 | a.idct36(a.sample[ch], p, a.v[ch], a.vPos) 432 | 433 | // Build U, windowing, calculate output 434 | for i := range a.u { 435 | a.u[i] = 0 436 | } 437 | 438 | dIndex := 512 - (a.vPos >> 1) 439 | vIndex := (a.vPos % 128) >> 1 440 | for vIndex < 1024 { 441 | for i := 0; i < 32; i++ { 442 | a.u[i] += a.d[dIndex] * a.v[ch][vIndex] 443 | dIndex++ 444 | vIndex++ 445 | } 446 | 447 | vIndex += 128 - 32 448 | dIndex += 64 - 32 449 | } 450 | 451 | dIndex -= 512 - 32 452 | vIndex = (128 - 32 + 1024) - vIndex 453 | for vIndex < 1024 { 454 | for i := 0; i < 32; i++ { 455 | a.u[i] += a.d[dIndex] * a.v[ch][vIndex] 456 | dIndex++ 457 | vIndex++ 458 | } 459 | 460 | vIndex += 128 - 32 461 | dIndex += 64 - 32 462 | } 463 | 464 | // Output samples 465 | var out []float32 466 | if ch == 0 { 467 | out = a.samples.Left 468 | } else { 469 | out = a.samples.Right 470 | } 471 | 472 | for j := 0; j < 32; j++ { 473 | s := a.u[j] / -1090519040.0 474 | 475 | switch a.format { 476 | case AudioF32N: 477 | a.samples.Interleaved[((outPos+j)<<1)+ch] = s 478 | case AudioF32NLR: 479 | out[outPos+j] = s 480 | case AudioS16: 481 | if s < 0 { 482 | a.samples.S16[((outPos+j)<<1)+ch] = int16(s * 0x8000) 483 | } else { 484 | a.samples.S16[((outPos+j)<<1)+ch] = int16(s * 0x7FFF) 485 | } 486 | case AudioF32: 487 | if s < 0 { 488 | a.samples.F32[((outPos+j)<<1)+ch] = s * 0x80000000 489 | } else { 490 | a.samples.F32[((outPos+j)<<1)+ch] = s * 0x7FFFFFFF 491 | } 492 | } 493 | } 494 | } // End of synthesis ch loop 495 | 496 | outPos += 32 497 | } // End of synthesis sub-block loop 498 | } // Decoding of the granule finished 499 | } 500 | 501 | a.buf.align() 502 | } 503 | 504 | func (a *Audio) readAllocation(sb, tab3 int) *quantizerSpec { 505 | tab4 := quantLutStep3[tab3][sb] 506 | qtab := quantLutStep4[tab4&15][a.buf.read(int(tab4)>>4)] 507 | 508 | if qtab != 0 { 509 | return &quantTab[qtab-1] 510 | } 511 | 512 | return nil 513 | } 514 | 515 | func (a *Audio) readSamples(ch, sb, part int) { 516 | q := a.allocation[ch][sb] 517 | sf := a.scaleFactor[ch][sb][part] 518 | val := 0 519 | 520 | if q == nil { 521 | // No bits allocated for this subband 522 | a.sample[ch][sb][0] = 0 523 | a.sample[ch][sb][1] = 0 524 | a.sample[ch][sb][2] = 0 525 | 526 | return 527 | } 528 | 529 | // Resolve scale factor 530 | if sf == 63 { 531 | sf = 0 532 | } else { 533 | shift := sf / 3 534 | sf = (scalefactorBase[sf%3] + ((1 << shift) >> 1)) >> shift 535 | } 536 | 537 | // Decode samples 538 | adj := int(q.Levels) 539 | if q.Group != 0 { 540 | // Decode grouped samples 541 | val = a.buf.read(int(q.Bits)) 542 | a.sample[ch][sb][0] = val % adj 543 | val /= adj 544 | a.sample[ch][sb][1] = val % adj 545 | a.sample[ch][sb][2] = val / adj 546 | } else { 547 | // Decode direct samples 548 | a.sample[ch][sb][0] = a.buf.read(int(q.Bits)) 549 | a.sample[ch][sb][1] = a.buf.read(int(q.Bits)) 550 | a.sample[ch][sb][2] = a.buf.read(int(q.Bits)) 551 | } 552 | 553 | // Postmultiply samples 554 | scale := 65536 / (adj + 1) 555 | adj = ((adj + 1) >> 1) - 1 556 | 557 | val = (adj - a.sample[ch][sb][0]) * scale 558 | a.sample[ch][sb][0] = (val*(sf>>12) + ((val*(sf&4095) + 2048) >> 12)) >> 12 559 | 560 | val = (adj - a.sample[ch][sb][1]) * scale 561 | a.sample[ch][sb][1] = (val*(sf>>12) + ((val*(sf&4095) + 2048) >> 12)) >> 12 562 | 563 | val = (adj - a.sample[ch][sb][2]) * scale 564 | a.sample[ch][sb][2] = (val*(sf>>12) + ((val*(sf&4095) + 2048) >> 12)) >> 12 565 | } 566 | 567 | func (a *Audio) idct36(s [32][3]int, ss int, d []float32, dp int) { 568 | var t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, 569 | t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24, 570 | t25, t26, t27, t28, t29, t30, t31, t32, t33 float32 571 | 572 | t01 = float32(s[0][ss] + s[31][ss]) 573 | t02 = float32(s[0][ss]-s[31][ss]) * 0.500602998235 574 | t03 = float32(s[1][ss] + s[30][ss]) 575 | t04 = float32(s[1][ss]-s[30][ss]) * 0.505470959898 576 | t05 = float32(s[2][ss] + s[29][ss]) 577 | t06 = float32(s[2][ss]-s[29][ss]) * 0.515447309923 578 | t07 = float32(s[3][ss] + s[28][ss]) 579 | t08 = float32(s[3][ss]-s[28][ss]) * 0.53104259109 580 | t09 = float32(s[4][ss] + s[27][ss]) 581 | t10 = float32(s[4][ss]-s[27][ss]) * 0.553103896034 582 | t11 = float32(s[5][ss] + s[26][ss]) 583 | t12 = float32(s[5][ss]-s[26][ss]) * 0.582934968206 584 | t13 = float32(s[6][ss] + s[25][ss]) 585 | t14 = float32(s[6][ss]-s[25][ss]) * 0.622504123036 586 | t15 = float32(s[7][ss] + s[24][ss]) 587 | t16 = float32(s[7][ss]-s[24][ss]) * 0.674808341455 588 | t17 = float32(s[8][ss] + s[23][ss]) 589 | t18 = float32(s[8][ss]-s[23][ss]) * 0.744536271002 590 | t19 = float32(s[9][ss] + s[22][ss]) 591 | t20 = float32(s[9][ss]-s[22][ss]) * 0.839349645416 592 | t21 = float32(s[10][ss] + s[21][ss]) 593 | t22 = float32(s[10][ss]-s[21][ss]) * 0.972568237862 594 | t23 = float32(s[11][ss] + s[20][ss]) 595 | t24 = float32(s[11][ss]-s[20][ss]) * 1.16943993343 596 | t25 = float32(s[12][ss] + s[19][ss]) 597 | t26 = float32(s[12][ss]-s[19][ss]) * 1.48416461631 598 | t27 = float32(s[13][ss] + s[18][ss]) 599 | t28 = float32(s[13][ss]-s[18][ss]) * 2.05778100995 600 | t29 = float32(s[14][ss] + s[17][ss]) 601 | t30 = float32(s[14][ss]-s[17][ss]) * 3.40760841847 602 | t31 = float32(s[15][ss] + s[16][ss]) 603 | t32 = float32(s[15][ss]-s[16][ss]) * 10.1900081235 604 | 605 | t33 = t01 + t31 606 | t31 = (t01 - t31) * 0.502419286188 607 | t01 = t03 + t29 608 | t29 = (t03 - t29) * 0.52249861494 609 | t03 = t05 + t27 610 | t27 = (t05 - t27) * 0.566944034816 611 | t05 = t07 + t25 612 | t25 = (t07 - t25) * 0.64682178336 613 | t07 = t09 + t23 614 | t23 = (t09 - t23) * 0.788154623451 615 | t09 = t11 + t21 616 | t21 = (t11 - t21) * 1.06067768599 617 | t11 = t13 + t19 618 | t19 = (t13 - t19) * 1.72244709824 619 | t13 = t15 + t17 620 | t17 = (t15 - t17) * 5.10114861869 621 | t15 = t33 + t13 622 | t13 = (t33 - t13) * 0.509795579104 623 | t33 = t01 + t11 624 | t01 = (t01 - t11) * 0.601344886935 625 | t11 = t03 + t09 626 | t09 = (t03 - t09) * 0.899976223136 627 | t03 = t05 + t07 628 | t07 = (t05 - t07) * 2.56291544774 629 | t05 = t15 + t03 630 | t15 = (t15 - t03) * 0.541196100146 631 | t03 = t33 + t11 632 | t11 = (t33 - t11) * 1.30656296488 633 | t33 = t05 + t03 634 | t05 = (t05 - t03) * 0.707106781187 635 | t03 = t15 + t11 636 | t15 = (t15 - t11) * 0.707106781187 637 | t03 += t15 638 | t11 = t13 + t07 639 | t13 = (t13 - t07) * 0.541196100146 640 | t07 = t01 + t09 641 | t09 = (t01 - t09) * 1.30656296488 642 | t01 = t11 + t07 643 | t07 = (t11 - t07) * 0.707106781187 644 | t11 = t13 + t09 645 | t13 = (t13 - t09) * 0.707106781187 646 | t11 += t13 647 | t01 += t11 648 | t11 += t07 649 | t07 += t13 650 | t09 = t31 + t17 651 | t31 = (t31 - t17) * 0.509795579104 652 | t17 = t29 + t19 653 | t29 = (t29 - t19) * 0.601344886935 654 | t19 = t27 + t21 655 | t21 = (t27 - t21) * 0.899976223136 656 | t27 = t25 + t23 657 | t23 = (t25 - t23) * 2.56291544774 658 | t25 = t09 + t27 659 | t09 = (t09 - t27) * 0.541196100146 660 | t27 = t17 + t19 661 | t19 = (t17 - t19) * 1.30656296488 662 | t17 = t25 + t27 663 | t27 = (t25 - t27) * 0.707106781187 664 | t25 = t09 + t19 665 | t19 = (t09 - t19) * 0.707106781187 666 | t25 += t19 667 | t09 = t31 + t23 668 | t31 = (t31 - t23) * 0.541196100146 669 | t23 = t29 + t21 670 | t21 = (t29 - t21) * 1.30656296488 671 | t29 = t09 + t23 672 | t23 = (t09 - t23) * 0.707106781187 673 | t09 = t31 + t21 674 | t31 = (t31 - t21) * 0.707106781187 675 | t09 += t31 676 | t29 += t09 677 | t09 += t23 678 | t23 += t31 679 | t17 += t29 680 | t29 += t25 681 | t25 += t09 682 | t09 += t27 683 | t27 += t23 684 | t23 += t19 685 | t19 += t31 686 | t21 = t02 + t32 687 | t02 = (t02 - t32) * 0.502419286188 688 | t32 = t04 + t30 689 | t04 = (t04 - t30) * 0.52249861494 690 | t30 = t06 + t28 691 | t28 = (t06 - t28) * 0.566944034816 692 | t06 = t08 + t26 693 | t08 = (t08 - t26) * 0.64682178336 694 | t26 = t10 + t24 695 | t10 = (t10 - t24) * 0.788154623451 696 | t24 = t12 + t22 697 | t22 = (t12 - t22) * 1.06067768599 698 | t12 = t14 + t20 699 | t20 = (t14 - t20) * 1.72244709824 700 | t14 = t16 + t18 701 | t16 = (t16 - t18) * 5.10114861869 702 | t18 = t21 + t14 703 | t14 = (t21 - t14) * 0.509795579104 704 | t21 = t32 + t12 705 | t32 = (t32 - t12) * 0.601344886935 706 | t12 = t30 + t24 707 | t24 = (t30 - t24) * 0.899976223136 708 | t30 = t06 + t26 709 | t26 = (t06 - t26) * 2.56291544774 710 | t06 = t18 + t30 711 | t18 = (t18 - t30) * 0.541196100146 712 | t30 = t21 + t12 713 | t12 = (t21 - t12) * 1.30656296488 714 | t21 = t06 + t30 715 | t30 = (t06 - t30) * 0.707106781187 716 | t06 = t18 + t12 717 | t12 = (t18 - t12) * 0.707106781187 718 | t06 += t12 719 | t18 = t14 + t26 720 | t26 = (t14 - t26) * 0.541196100146 721 | t14 = t32 + t24 722 | t24 = (t32 - t24) * 1.30656296488 723 | t32 = t18 + t14 724 | t14 = (t18 - t14) * 0.707106781187 725 | t18 = t26 + t24 726 | t24 = (t26 - t24) * 0.707106781187 727 | t18 += t24 728 | t32 += t18 729 | t18 += t14 730 | t26 = t14 + t24 731 | t14 = t02 + t16 732 | t02 = (t02 - t16) * 0.509795579104 733 | t16 = t04 + t20 734 | t04 = (t04 - t20) * 0.601344886935 735 | t20 = t28 + t22 736 | t22 = (t28 - t22) * 0.899976223136 737 | t28 = t08 + t10 738 | t10 = (t08 - t10) * 2.56291544774 739 | t08 = t14 + t28 740 | t14 = (t14 - t28) * 0.541196100146 741 | t28 = t16 + t20 742 | t20 = (t16 - t20) * 1.30656296488 743 | t16 = t08 + t28 744 | t28 = (t08 - t28) * 0.707106781187 745 | t08 = t14 + t20 746 | t20 = (t14 - t20) * 0.707106781187 747 | t08 += t20 748 | t14 = t02 + t10 749 | t02 = (t02 - t10) * 0.541196100146 750 | t10 = t04 + t22 751 | t22 = (t04 - t22) * 1.30656296488 752 | t04 = t14 + t10 753 | t10 = (t14 - t10) * 0.707106781187 754 | t14 = t02 + t22 755 | t02 = (t02 - t22) * 0.707106781187 756 | t14 += t02 757 | t04 += t14 758 | t14 += t10 759 | t10 += t02 760 | t16 += t04 761 | t04 += t08 762 | t08 += t14 763 | t14 += t28 764 | t28 += t10 765 | t10 += t20 766 | t20 += t02 767 | t21 += t16 768 | t16 += t32 769 | t32 += t04 770 | t04 += t06 771 | t06 += t08 772 | t08 += t18 773 | t18 += t14 774 | t14 += t30 775 | t30 += t28 776 | t28 += t26 777 | t26 += t10 778 | t10 += t12 779 | t12 += t20 780 | t20 += t24 781 | t24 += t02 782 | 783 | d[dp+48] = -t33 784 | d[dp+49] = -t21 785 | d[dp+47] = -t21 786 | d[dp+50] = -t17 787 | d[dp+46] = -t17 788 | d[dp+51] = -t16 789 | d[dp+45] = -t16 790 | d[dp+52] = -t01 791 | d[dp+44] = -t01 792 | d[dp+53] = -t32 793 | d[dp+43] = -t32 794 | d[dp+54] = -t29 795 | d[dp+42] = -t29 796 | d[dp+55] = -t04 797 | d[dp+41] = -t04 798 | d[dp+56] = -t03 799 | d[dp+40] = -t03 800 | d[dp+57] = -t06 801 | d[dp+39] = -t06 802 | d[dp+58] = -t25 803 | d[dp+38] = -t25 804 | d[dp+59] = -t08 805 | d[dp+37] = -t08 806 | d[dp+60] = -t11 807 | d[dp+36] = -t11 808 | d[dp+61] = -t18 809 | d[dp+35] = -t18 810 | d[dp+62] = -t09 811 | d[dp+34] = -t09 812 | d[dp+63] = -t14 813 | d[dp+33] = -t14 814 | d[dp+32] = -t05 815 | d[dp+0] = t05 816 | d[dp+31] = -t30 817 | d[dp+1] = t30 818 | d[dp+30] = -t27 819 | d[dp+2] = t27 820 | d[dp+29] = -t28 821 | d[dp+3] = t28 822 | d[dp+28] = -t07 823 | d[dp+4] = t07 824 | d[dp+27] = -t26 825 | d[dp+5] = t26 826 | d[dp+26] = -t23 827 | d[dp+6] = t23 828 | d[dp+25] = -t10 829 | d[dp+7] = t10 830 | d[dp+24] = -t15 831 | d[dp+8] = t15 832 | d[dp+23] = -t12 833 | d[dp+9] = t12 834 | d[dp+22] = -t19 835 | d[dp+10] = t19 836 | d[dp+21] = -t20 837 | d[dp+11] = t20 838 | d[dp+20] = -t13 839 | d[dp+12] = t13 840 | d[dp+19] = -t24 841 | d[dp+13] = t24 842 | d[dp+18] = -t31 843 | d[dp+14] = t31 844 | d[dp+17] = -t02 845 | d[dp+15] = t02 846 | d[dp+16] = 0.0 847 | } 848 | 849 | const ( 850 | frameSync = 0x7ff 851 | 852 | mpeg25 = 0x0 853 | mpeg2 = 0x2 854 | mpeg1 = 0x3 855 | 856 | layerIII = 0x1 857 | layerII = 0x2 858 | layerI = 0x3 859 | 860 | modeStereo = 0x0 861 | modeJointStereo = 0x1 862 | modeDualChannel = 0x2 863 | modeMono = 0x3 864 | ) 865 | 866 | // quantizerSpec . 867 | type quantizerSpec struct { 868 | Levels uint16 869 | Group uint8 870 | Bits uint8 871 | } 872 | 873 | var samplerate = []uint16{ 874 | 44100, 48000, 32000, 0, // MPEG-1 875 | 22050, 24000, 16000, 0, // MPEG-2 876 | } 877 | 878 | var bitrate = []int16{ 879 | 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, // MPEG-1 880 | 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, // MPEG-2 881 | } 882 | 883 | var scalefactorBase = []int{ 884 | 0x02000000, 0x01965FEA, 0x01428A30, 885 | } 886 | 887 | var synthesisWindow = []float32{ 888 | 0.0, -0.5, -0.5, -0.5, -0.5, -0.5, 889 | -0.5, -1.0, -1.0, -1.0, -1.0, -1.5, 890 | -1.5, -2.0, -2.0, -2.5, -2.5, -3.0, 891 | -3.5, -3.5, -4.0, -4.5, -5.0, -5.5, 892 | -6.5, -7.0, -8.0, -8.5, -9.5, -10.5, 893 | -12.0, -13.0, -14.5, -15.5, -17.5, -19.0, 894 | -20.5, -22.5, -24.5, -26.5, -29.0, -31.5, 895 | -34.0, -36.5, -39.5, -42.5, -45.5, -48.5, 896 | -52.0, -55.5, -58.5, -62.5, -66.0, -69.5, 897 | -73.5, -77.0, -80.5, -84.5, -88.0, -91.5, 898 | -95.0, -98.0, -101.0, -104.0, 106.5, 109.0, 899 | 111.0, 112.5, 113.5, 114.0, 114.0, 113.5, 900 | 112.0, 110.5, 107.5, 104.0, 100.0, 94.5, 901 | 88.5, 81.5, 73.0, 63.5, 53.0, 41.5, 902 | 28.5, 14.5, -1.0, -18.0, -36.0, -55.5, 903 | -76.5, -98.5, -122.0, -147.0, -173.5, -200.5, 904 | -229.5, -259.5, -290.5, -322.5, -355.5, -389.5, 905 | -424.0, -459.5, -495.5, -532.0, -568.5, -605.0, 906 | -641.5, -678.0, -714.0, -749.0, -783.5, -817.0, 907 | -849.0, -879.5, -908.5, -935.0, -959.5, -981.0, 908 | -1000.5, -1016.0, -1028.5, -1037.5, -1042.5, -1043.5, 909 | -1040.0, -1031.5, 1018.5, 1000.0, 976.0, 946.5, 910 | 911.0, 869.5, 822.0, 767.5, 707.0, 640.0, 911 | 565.5, 485.0, 397.0, 302.5, 201.0, 92.5, 912 | -22.5, -144.0, -272.5, -407.0, -547.5, -694.0, 913 | -846.0, -1003.0, -1165.0, -1331.5, -1502.0, -1675.5, 914 | -1852.5, -2031.5, -2212.5, -2394.0, -2576.5, -2758.5, 915 | -2939.5, -3118.5, -3294.5, -3467.5, -3635.5, -3798.5, 916 | -3955.0, -4104.5, -4245.5, -4377.5, -4499.0, -4609.5, 917 | -4708.0, -4792.5, -4863.5, -4919.0, -4958.0, -4979.5, 918 | -4983.0, -4967.5, -4931.5, -4875.0, -4796.0, -4694.5, 919 | -4569.5, -4420.0, -4246.0, -4046.0, -3820.0, -3567.0, 920 | 3287.0, 2979.5, 2644.0, 2280.5, 1888.0, 1467.5, 921 | 1018.5, 541.0, 35.0, -499.0, -1061.0, -1650.0, 922 | -2266.5, -2909.0, -3577.0, -4270.0, -4987.5, -5727.5, 923 | -6490.0, -7274.0, -8077.5, -8899.5, -9739.0, -10594.5, 924 | -11464.5, -12347.0, -13241.0, -14144.5, -15056.0, -15973.5, 925 | -16895.5, -17820.0, -18744.5, -19668.0, -20588.0, -21503.0, 926 | -22410.5, -23308.5, -24195.0, -25068.5, -25926.5, -26767.0, 927 | -27589.0, -28389.0, -29166.5, -29919.0, -30644.5, -31342.0, 928 | -32009.5, -32645.0, -33247.0, -33814.5, -34346.0, -34839.5, 929 | -35295.0, -35710.0, -36084.5, -36417.5, -36707.5, -36954.0, 930 | -37156.5, -37315.0, -37428.0, -37496.0, 37519.0, 37496.0, 931 | 37428.0, 37315.0, 37156.5, 36954.0, 36707.5, 36417.5, 932 | 36084.5, 35710.0, 35295.0, 34839.5, 34346.0, 33814.5, 933 | 33247.0, 32645.0, 32009.5, 31342.0, 30644.5, 29919.0, 934 | 29166.5, 28389.0, 27589.0, 26767.0, 25926.5, 25068.5, 935 | 24195.0, 23308.5, 22410.5, 21503.0, 20588.0, 19668.0, 936 | 18744.5, 17820.0, 16895.5, 15973.5, 15056.0, 14144.5, 937 | 13241.0, 12347.0, 11464.5, 10594.5, 9739.0, 8899.5, 938 | 8077.5, 7274.0, 6490.0, 5727.5, 4987.5, 4270.0, 939 | 3577.0, 2909.0, 2266.5, 1650.0, 1061.0, 499.0, 940 | -35.0, -541.0, -1018.5, -1467.5, -1888.0, -2280.5, 941 | -2644.0, -2979.5, 3287.0, 3567.0, 3820.0, 4046.0, 942 | 4246.0, 4420.0, 4569.5, 4694.5, 4796.0, 4875.0, 943 | 4931.5, 4967.5, 4983.0, 4979.5, 4958.0, 4919.0, 944 | 4863.5, 4792.5, 4708.0, 4609.5, 4499.0, 4377.5, 945 | 4245.5, 4104.5, 3955.0, 3798.5, 3635.5, 3467.5, 946 | 3294.5, 3118.5, 2939.5, 2758.5, 2576.5, 2394.0, 947 | 2212.5, 2031.5, 1852.5, 1675.5, 1502.0, 1331.5, 948 | 1165.0, 1003.0, 846.0, 694.0, 547.5, 407.0, 949 | 272.5, 144.0, 22.5, -92.5, -201.0, -302.5, 950 | -397.0, -485.0, -565.5, -640.0, -707.0, -767.5, 951 | -822.0, -869.5, -911.0, -946.5, -976.0, -1000.0, 952 | 1018.5, 1031.5, 1040.0, 1043.5, 1042.5, 1037.5, 953 | 1028.5, 1016.0, 1000.5, 981.0, 959.5, 935.0, 954 | 908.5, 879.5, 849.0, 817.0, 783.5, 749.0, 955 | 714.0, 678.0, 641.5, 605.0, 568.5, 532.0, 956 | 495.5, 459.5, 424.0, 389.5, 355.5, 322.5, 957 | 290.5, 259.5, 229.5, 200.5, 173.5, 147.0, 958 | 122.0, 98.5, 76.5, 55.5, 36.0, 18.0, 959 | 1.0, -14.5, -28.5, -41.5, -53.0, -63.5, 960 | -73.0, -81.5, -88.5, -94.5, -100.0, -104.0, 961 | -107.5, -110.5, -112.0, -113.5, -114.0, -114.0, 962 | -113.5, -112.5, -111.0, -109.0, 106.5, 104.0, 963 | 101.0, 98.0, 95.0, 91.5, 88.0, 84.5, 964 | 80.5, 77.0, 73.5, 69.5, 66.0, 62.5, 965 | 58.5, 55.5, 52.0, 48.5, 45.5, 42.5, 966 | 39.5, 36.5, 34.0, 31.5, 29.0, 26.5, 967 | 24.5, 22.5, 20.5, 19.0, 17.5, 15.5, 968 | 14.5, 13.0, 12.0, 10.5, 9.5, 8.5, 969 | 8.0, 7.0, 6.5, 5.5, 5.0, 4.5, 970 | 4.0, 3.5, 3.5, 3.0, 2.5, 2.5, 971 | 2.0, 2.0, 1.5, 1.5, 1.0, 1.0, 972 | 1.0, 1.0, 0.5, 0.5, 0.5, 0.5, 973 | 0.5, 0.5, 974 | } 975 | 976 | // Quantizer lookup, step 1: bitrate classes. 977 | var quantLutStep1 = [][]byte{ 978 | // 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384 <- bitrate 979 | {0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, // mono 980 | // 16, 24, 28, 32, 40, 48, 56, 64, 80, 96,112,128,160,192 <- bitrate / chan 981 | {0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2}, // stereo 982 | } 983 | 984 | // Quantizer lookup, step 2: bitrate class, sample rate -> B2 table idx, sblimit. 985 | var quantTabA = byte(27 | 64) // Table 3-B.2a: high-rate, sblimit = 27 986 | var quantTabB = byte(30 | 64) // Table 3-B.2b: high-rate, sblimit = 30 987 | var quantTabC = byte(8) // Table 3-B.2c: low-rate, sblimit = 8 988 | var quantTabD = byte(12) // Table 3-B.2d: low-rate, sblimit = 12 989 | 990 | var quantLutStep2 = [][]byte{ 991 | // 44.1 kHz, 48 kHz, 32 kHz 992 | {quantTabC, quantTabC, quantTabD}, // 32 - 48 kbit/sec/ch 993 | {quantTabA, quantTabA, quantTabA}, // 56 - 80 kbit/sec/ch 994 | {quantTabB, quantTabA, quantTabB}, // 96+ kbit/sec/ch 995 | } 996 | 997 | // Quantizer lookup, step 3: B2 table, subband -> nbal, row Index (upper 4 bits: nbal, lower 4 bits: row Index). 998 | var quantLutStep3 = [][]byte{ 999 | // Low-rate table (3-B.2c and 3-B.2d) 1000 | { 1001 | 0x44, 0x44, 1002 | 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 1003 | }, 1004 | // High-rate table (3-B.2a and 3-B.2b) 1005 | { 1006 | 0x43, 0x43, 0x43, 1007 | 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 1008 | 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 1009 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 1010 | }, 1011 | // MPEG-2 LSR table (B.2 in ISO 13818-3) 1012 | { 1013 | 0x45, 0x45, 0x45, 0x45, 1014 | 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 1015 | 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 1016 | 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 1017 | }, 1018 | } 1019 | 1020 | // Quantizer lookup, step 4: table row, allocation[] Value -> quant table Index. 1021 | var quantLutStep4 = [][]byte{ 1022 | {0, 1, 2, 17}, 1023 | {0, 1, 2, 3, 4, 5, 6, 17}, 1024 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17}, 1025 | {0, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}, 1026 | {0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, 1027 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 1028 | } 1029 | 1030 | var quantTab = []quantizerSpec{ 1031 | {3, 1, 5}, // 1 1032 | {5, 1, 7}, // 2 1033 | {7, 0, 3}, // 3 1034 | {9, 1, 10}, // 4 1035 | {15, 0, 4}, // 5 1036 | {31, 0, 5}, // 6 1037 | {63, 0, 6}, // 7 1038 | {127, 0, 7}, // 8 1039 | {255, 0, 8}, // 9 1040 | {511, 0, 9}, // 10 1041 | {1023, 0, 10}, // 11 1042 | {2047, 0, 11}, // 12 1043 | {4095, 0, 12}, // 13 1044 | {8191, 0, 13}, // 14 1045 | {16383, 0, 14}, // 15 1046 | {32767, 0, 15}, // 16 1047 | {65535, 0, 16}, // 17 1048 | } 1049 | -------------------------------------------------------------------------------- /buffer.go: -------------------------------------------------------------------------------- 1 | package mpeg 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | var ( 8 | // BufferSize is the default size for buffer. 9 | BufferSize = 128 * 1024 10 | ) 11 | 12 | // LoadFunc callback function. 13 | type LoadFunc func(buffer *Buffer) 14 | 15 | // Buffer provides the data source for all other interfaces. 16 | type Buffer struct { 17 | reader io.Reader 18 | bytes []byte 19 | 20 | bitIndex int 21 | totalSize int 22 | 23 | hasEnded bool 24 | discardRead bool 25 | 26 | available []byte 27 | loadCallback LoadFunc 28 | } 29 | 30 | // NewBuffer creates a buffer instance. 31 | func NewBuffer(r io.Reader) (*Buffer, error) { 32 | buf := &Buffer{} 33 | 34 | if r != nil { 35 | seeker, ok := r.(io.Seeker) 36 | if ok { 37 | cur, err := seeker.Seek(0, io.SeekCurrent) 38 | if err != nil { 39 | return nil, err 40 | } 41 | off, err := seeker.Seek(0, io.SeekEnd) 42 | if err != nil { 43 | return nil, err 44 | } 45 | buf.totalSize = int(off) 46 | _, err = seeker.Seek(cur, io.SeekStart) 47 | if err != nil { 48 | return nil, err 49 | } 50 | } 51 | } 52 | 53 | buf.reader = r 54 | buf.bytes = make([]byte, 0, BufferSize) 55 | buf.available = make([]byte, BufferSize) 56 | 57 | buf.discardRead = true 58 | 59 | return buf, nil 60 | } 61 | 62 | // Bytes returns a slice holding the unread portion of the buffer. 63 | func (b *Buffer) Bytes() []byte { 64 | return b.bytes 65 | } 66 | 67 | // Index returns byte index. 68 | func (b *Buffer) Index() int { 69 | return b.bitIndex >> 3 70 | } 71 | 72 | // Seekable returns true if reader is seekable. 73 | func (b *Buffer) Seekable() bool { 74 | return b.reader != nil && b.totalSize > 0 75 | } 76 | 77 | // Write appends the contents of p to the buffer. 78 | func (b *Buffer) Write(p []byte) int { 79 | if b.discardRead { 80 | b.discardReadBytes() 81 | } 82 | 83 | b.bytes = append(b.bytes, p...) 84 | 85 | b.hasEnded = false 86 | 87 | return len(p) 88 | } 89 | 90 | // SignalEnd marks the current byte length as the end of this buffer and signal that no 91 | // more data is expected to be written to it. This function should be called 92 | // just after the last Write(). 93 | func (b *Buffer) SignalEnd() { 94 | b.totalSize = len(b.bytes) 95 | } 96 | 97 | // SetLoadCallback sets a callback that is called whenever the buffer needs more data. 98 | func (b *Buffer) SetLoadCallback(callback LoadFunc) { 99 | b.loadCallback = callback 100 | } 101 | 102 | // Rewind the buffer back to the beginning. When loading from io.ReadSeeker, 103 | // this also seeks to the beginning. 104 | func (b *Buffer) Rewind() { 105 | b.seek(0) 106 | } 107 | 108 | // Size returns the total size. For io.ReadSeeker, this returns the total size. For all other 109 | // types it returns the number of bytes currently in the buffer. 110 | func (b *Buffer) Size() int { 111 | if b.totalSize > 0 { 112 | return b.totalSize 113 | } 114 | 115 | return len(b.bytes) 116 | } 117 | 118 | // Remaining returns the number of remaining (yet unread) bytes in the buffer. 119 | // This can be useful to throttle writing. 120 | func (b *Buffer) Remaining() int { 121 | return len(b.bytes) - (b.bitIndex >> 3) 122 | } 123 | 124 | // HasEnded checks whether the read position of the buffer is at the end and no more data is expected. 125 | func (b *Buffer) HasEnded() bool { 126 | return b.hasEnded 127 | } 128 | 129 | // LoadReaderCallback is a callback that is called whenever the buffer needs more data. 130 | func (b *Buffer) LoadReaderCallback(buffer *Buffer) { 131 | if b.hasEnded { 132 | return 133 | } 134 | 135 | p := b.available 136 | 137 | n, err := io.ReadFull(b.reader, p) 138 | if err != nil { 139 | if err == io.ErrUnexpectedEOF { 140 | p = p[:n] 141 | } else if err == io.EOF { 142 | b.hasEnded = true 143 | 144 | return 145 | } 146 | } 147 | 148 | if n == 0 { 149 | b.hasEnded = true 150 | 151 | return 152 | } 153 | 154 | b.Write(p) 155 | } 156 | 157 | func (b *Buffer) seek(pos int) { 158 | b.hasEnded = false 159 | 160 | if b.reader != nil && b.totalSize > 0 { 161 | seeker := b.reader.(io.Seeker) 162 | _, _ = seeker.Seek(int64(pos), io.SeekStart) 163 | b.bytes = b.bytes[:0] 164 | 165 | b.bitIndex = 0 166 | } else if b.reader == nil { 167 | if pos != 0 { 168 | return 169 | } 170 | 171 | b.bytes = b.bytes[:0] 172 | 173 | b.bitIndex = 0 174 | } 175 | } 176 | 177 | func (b *Buffer) tell() int { 178 | if b.reader != nil && b.totalSize > 0 { 179 | seeker := b.reader.(io.Seeker) 180 | off, _ := seeker.Seek(0, io.SeekCurrent) 181 | 182 | return int(off) + (b.bitIndex >> 3) - len(b.bytes) 183 | } 184 | 185 | return b.bitIndex >> 3 186 | } 187 | 188 | func (b *Buffer) discardReadBytes() { 189 | bytePos := b.bitIndex >> 3 190 | if bytePos == len(b.bytes) { 191 | b.bytes = b.bytes[:0] 192 | 193 | b.bitIndex = 0 194 | } else if bytePos > 0 { 195 | copy(b.bytes, b.bytes[bytePos:]) 196 | b.bytes = b.bytes[:len(b.bytes)-bytePos] 197 | 198 | b.bitIndex -= bytePos << 3 199 | } 200 | } 201 | 202 | func (b *Buffer) has(count int) bool { 203 | if ((len(b.bytes) << 3) - b.bitIndex) >= count { 204 | return true 205 | } 206 | 207 | if b.loadCallback != nil { 208 | b.loadCallback(b) 209 | 210 | if ((len(b.bytes) << 3) - b.bitIndex) >= count { 211 | return true 212 | } 213 | } 214 | 215 | if b.totalSize != 0 && len(b.bytes) == b.totalSize { 216 | b.hasEnded = true 217 | } 218 | 219 | return false 220 | } 221 | 222 | func (b *Buffer) read(count int) int { 223 | if !b.has(count) { 224 | return 0 225 | } 226 | 227 | value := 0 228 | for count != 0 { 229 | currentByte := int(b.Bytes()[b.bitIndex>>3]) 230 | 231 | remaining := 8 - (b.bitIndex & 7) // Remaining bits in byte 232 | read := count 233 | if remaining < count { // Bits in self run 234 | read = remaining 235 | } 236 | 237 | shift := remaining - read 238 | mask := 0xff >> (8 - read) 239 | 240 | value = (value << read) | ((currentByte & (mask << shift)) >> shift) 241 | 242 | b.bitIndex += read 243 | count -= read 244 | } 245 | 246 | return value 247 | } 248 | 249 | func (b *Buffer) read1() int { 250 | if !b.has(1) { 251 | return 0 252 | } 253 | 254 | currentByte := int(b.Bytes()[b.bitIndex>>3]) 255 | 256 | shift := 7 - (b.bitIndex & 7) 257 | value := (currentByte & (1 << shift)) >> shift 258 | 259 | b.bitIndex += 1 260 | 261 | return value 262 | } 263 | 264 | func (b *Buffer) align() { 265 | b.bitIndex = ((b.bitIndex + 7) >> 3) << 3 // Align to next byte 266 | } 267 | 268 | func (b *Buffer) skip(count int) { 269 | if b.has(count) { 270 | b.bitIndex += count 271 | } 272 | } 273 | 274 | func (b *Buffer) skipBytes(v byte) int { 275 | b.align() 276 | 277 | skipped := 0 278 | for b.has(8) && b.Bytes()[b.bitIndex>>3] == v { 279 | b.bitIndex += 8 280 | skipped++ 281 | } 282 | 283 | return skipped 284 | } 285 | 286 | func (b *Buffer) nextStartCode() int { 287 | b.align() 288 | 289 | for b.has(5 << 3) { 290 | data := b.Bytes() 291 | byteIndex := b.bitIndex >> 3 292 | if data[byteIndex] == 0x00 && 293 | data[byteIndex+1] == 0x00 && 294 | data[byteIndex+2] == 0x01 { 295 | b.bitIndex = (byteIndex + 4) << 3 296 | 297 | return int(data[byteIndex+3]) 298 | } 299 | 300 | b.bitIndex += 8 301 | } 302 | 303 | return -1 304 | } 305 | 306 | func (b *Buffer) findStartCode(code int) int { 307 | for { 308 | current := b.nextStartCode() 309 | if current == code || current == -1 { 310 | return current 311 | } 312 | } 313 | } 314 | 315 | func (b *Buffer) hasStartCode(code int) int { 316 | prevBitIndex := b.bitIndex 317 | prevDiscardRead := b.discardRead 318 | 319 | b.discardRead = false 320 | current := b.findStartCode(code) 321 | 322 | b.bitIndex = prevBitIndex 323 | b.discardRead = prevDiscardRead 324 | 325 | return current 326 | } 327 | 328 | func (b *Buffer) findFrameSync() bool { 329 | var i int 330 | for i = b.bitIndex >> 3; i < len(b.bytes)-1; i++ { 331 | if b.Bytes()[i] == 0xFF && (b.Bytes()[i+1]&0xFE) == 0xFC { 332 | b.bitIndex = ((i + 1) << 3) + 3 333 | 334 | return true 335 | } 336 | } 337 | 338 | b.bitIndex = (i + 1) << 3 339 | 340 | return false 341 | } 342 | 343 | func (b *Buffer) peekNonZero(bitCount int) bool { 344 | if !b.has(bitCount) { 345 | return false 346 | } 347 | 348 | val := b.read(bitCount) 349 | b.bitIndex -= bitCount 350 | 351 | return val != 0 352 | } 353 | 354 | func (b *Buffer) readVlc(table []vlc) int { 355 | var state vlc 356 | 357 | for { 358 | state = table[int(state.Index)+b.read1()] 359 | if state.Index <= 0 { 360 | break 361 | } 362 | } 363 | 364 | return int(state.Value) 365 | } 366 | 367 | func (b *Buffer) readVlcUint(table []vlcUint) uint16 { 368 | var state vlcUint 369 | 370 | for { 371 | state = table[int(state.Index)+b.read1()] 372 | if state.Index <= 0 { 373 | break 374 | } 375 | } 376 | 377 | return state.Value 378 | } 379 | 380 | type vlc struct { 381 | Index int16 382 | Value int16 383 | } 384 | 385 | type vlcUint struct { 386 | Index int16 387 | Value uint16 388 | } 389 | -------------------------------------------------------------------------------- /demux.go: -------------------------------------------------------------------------------- 1 | package mpeg 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // Packet is demuxed MPEG PS packet. 8 | // The Type maps directly to the various MPEG-PES start codes. 9 | // Pts is the presentation time stamp of the packet in seconds (not all packets have a pts Value). 10 | type Packet struct { 11 | Type int 12 | Pts float64 13 | Data []byte 14 | 15 | length int 16 | } 17 | 18 | // Various packet types. 19 | const ( 20 | PacketInvalidTS = -1 21 | 22 | PacketPrivate = 0xBD 23 | PacketAudio1 = 0xC0 24 | PacketAudio2 = 0xC1 25 | PacketAudio3 = 0xC2 26 | PacketAudio4 = 0xC3 27 | PacketVideo1 = 0xE0 28 | ) 29 | 30 | // ErrInvalidHeader is the error returned when pack and system headers are not found. 31 | var ErrInvalidHeader = errors.New("invalid MPEG-PS header") 32 | 33 | // Demux an MPEG Program Stream (PS) data into separate packages. 34 | type Demux struct { 35 | buf *Buffer 36 | 37 | sysClockRef float64 38 | lastFileSize int 39 | lastDecodedPts float64 40 | startTime float64 41 | duration float64 42 | 43 | startCode int 44 | hasPackHeader bool 45 | hasSystemHeader bool 46 | hasHeaders bool 47 | 48 | numAudioStreams int 49 | numVideoStreams int 50 | 51 | currentPacket Packet 52 | nextPacket Packet 53 | } 54 | 55 | // NewDemux creates a demuxer with buffer as a source. 56 | func NewDemux(buf *Buffer) (*Demux, error) { 57 | dmux := &Demux{} 58 | 59 | dmux.buf = buf 60 | dmux.startTime = PacketInvalidTS 61 | dmux.duration = PacketInvalidTS 62 | dmux.startCode = -1 63 | 64 | if !dmux.HasHeaders() { 65 | return nil, ErrInvalidHeader 66 | } 67 | 68 | return dmux, nil 69 | } 70 | 71 | // Buffer returns demuxer buffer. 72 | func (d *Demux) Buffer() *Buffer { 73 | return d.buf 74 | } 75 | 76 | // HasHeaders checks whether pack and system headers have been found. 77 | // This will attempt to read the headers if non are present yet. 78 | func (d *Demux) HasHeaders() bool { 79 | if d.hasHeaders { 80 | return true 81 | } 82 | 83 | // Decode pack header 84 | if !d.hasPackHeader { 85 | if d.startCode != startPack && d.buf.findStartCode(startPack) == -1 { 86 | return false 87 | } 88 | 89 | d.startCode = startPack 90 | if !d.buf.has(64) { 91 | return false 92 | } 93 | d.startCode = -1 94 | 95 | if d.buf.read(4) != 0x02 { 96 | return false 97 | } 98 | 99 | d.sysClockRef = d.decodeTime() 100 | d.buf.skip(1) 101 | d.buf.skip(22) // muxRate * 50 102 | d.buf.skip(1) 103 | 104 | d.hasPackHeader = true 105 | } 106 | 107 | // Decode system header 108 | if !d.hasSystemHeader { 109 | if d.startCode != startSystem && d.buf.findStartCode(startSystem) == -1 { 110 | return false 111 | } 112 | 113 | d.startCode = startSystem 114 | if !d.buf.has(56) { 115 | return false 116 | } 117 | d.startCode = -1 118 | 119 | d.buf.skip(16) // header length 120 | d.buf.skip(24) // rate bound 121 | d.numAudioStreams = d.buf.read(6) 122 | d.buf.skip(5) // misc flags 123 | d.numVideoStreams = d.buf.read(5) 124 | 125 | d.hasSystemHeader = true 126 | } 127 | 128 | d.hasHeaders = true 129 | 130 | return true 131 | } 132 | 133 | // NumVideoStreams returns the number of video streams found in the system header. 134 | func (d *Demux) NumVideoStreams() int { 135 | if d.HasHeaders() { 136 | return d.numVideoStreams 137 | } 138 | 139 | return 0 140 | } 141 | 142 | // NumAudioStreams returns the number of audio streams found in the system header. 143 | func (d *Demux) NumAudioStreams() int { 144 | if d.HasHeaders() { 145 | return d.numAudioStreams 146 | } 147 | 148 | return 0 149 | } 150 | 151 | // Rewind rewinds the internal buffer. 152 | func (d *Demux) Rewind() { 153 | d.buf.Rewind() 154 | d.currentPacket.length = 0 155 | d.nextPacket.length = 0 156 | d.startCode = -1 157 | } 158 | 159 | // HasEnded checks whether the file has ended. This will be cleared on seeking or rewind. 160 | func (d *Demux) HasEnded() bool { 161 | return d.buf.HasEnded() 162 | } 163 | 164 | // Seek seeks to a packet of the specified type with a PTS just before specified time. 165 | // If forceIntra is true, only packets containing an intra frame will be 166 | // considered - this only makes sense when the type is video. 167 | // Note that the specified time is considered 0-based, regardless of the first PTS in the data source. 168 | func (d *Demux) Seek(seekTime float64, typ int, forceIntra bool) *Packet { 169 | if !d.hasHeaders { 170 | return nil 171 | } 172 | 173 | // Using the current time, current byte position and the average bytes per 174 | // second for this file, try to jump to a byte position that hopefully has 175 | // packets containing timestamps within one second before to the desired seekTime. 176 | 177 | // If we hit close to the seekTime scan through all packets to find the 178 | // last one (just before the seekTime) containing an intra frame. 179 | // Otherwise, we should at least be closer than before. Calculate the bytes 180 | // per second for the jumped range and jump again. 181 | 182 | // The number of retries here is hard-limited to a generous amount. Usually 183 | // the correct range is found after 1-5 jumps, even for files with very 184 | // variable bitrates. If significantly more jumps are needed, there's 185 | // probably something wrong with the file, and we just avoid getting into an 186 | // infinite loop. 32 retries should be enough for anybody. 187 | 188 | duration := d.Duration(typ) 189 | fileSize := d.buf.Size() 190 | byteRate := float64(fileSize) / duration 191 | 192 | curTime := d.lastDecodedPts 193 | scanSpan := float64(1) 194 | 195 | if seekTime > duration { 196 | seekTime = duration 197 | } else if seekTime < 0 { 198 | seekTime = 0 199 | } 200 | seekTime += d.startTime 201 | 202 | for retry := 0; retry < 32; retry++ { 203 | foundPacketWithPts := false 204 | foundPacketInRange := false 205 | lastValidPacketStart := -1 206 | firstPacketTime := float64(PacketInvalidTS) 207 | 208 | curPos := d.buf.tell() 209 | 210 | // Estimate byte offset and jump to it. 211 | offset := (seekTime - curTime - scanSpan) * byteRate 212 | seekPos := curPos + int(offset) 213 | if seekPos < 0 { 214 | seekPos = 0 215 | } else if seekPos > fileSize-256 { 216 | seekPos = fileSize - 256 217 | } 218 | 219 | d.bufferSeek(seekPos) 220 | 221 | // Scan through all packets up to the seekTime to find the last packet 222 | // containing an intra frame. 223 | for d.buf.findStartCode(typ) != -1 { 224 | packetStart := d.buf.tell() 225 | packet := d.decodePacket(typ) 226 | 227 | // skip packet if it has no PTS 228 | if packet == nil || packet.Pts == PacketInvalidTS { 229 | continue 230 | } 231 | 232 | // Bail scanning through packets if we hit one that is outside seekTime - scanSpan. 233 | // We also adjust the curTime and byteRate values here so the next iteration can be a bit more precise. 234 | if packet.Pts > seekTime || packet.Pts < seekTime-scanSpan { 235 | foundPacketWithPts = true 236 | byteRate = float64(seekPos-curPos) / (packet.Pts - curTime) 237 | curTime = packet.Pts 238 | 239 | break 240 | } 241 | 242 | // If we are still here, it means this packet is in close range to 243 | // the seekTime. If this is the first packet for this jump position 244 | // record the PTS. If we later have to back off, when there was no 245 | // intra frame in this range, we can lower the seekTime to not scan 246 | // this range again. 247 | if !foundPacketInRange { 248 | foundPacketInRange = true 249 | firstPacketTime = packet.Pts 250 | } 251 | 252 | // Check if this is an intra frame packet. If so, record the buffer 253 | // position of the start of this packet. We want to jump back to it 254 | // later, when we know it's the last intra frame before desired 255 | // seek time. 256 | if forceIntra { 257 | for i := 0; i < packet.length-6; i++ { 258 | // Find the startPicture code 259 | if packet.Data[i] == 0x00 && 260 | packet.Data[i+1] == 0x00 && 261 | packet.Data[i+2] == 0x01 && 262 | packet.Data[i+3] == 0x00 { 263 | // Bits 11--13 in the picture header contain the frame type, where 1=Intra 264 | if (packet.Data[i+5] & 0x38) == 8 { 265 | lastValidPacketStart = packetStart 266 | } 267 | 268 | break 269 | } 270 | } 271 | } else { // If we don't want intra frames, just use the last PTS found. 272 | lastValidPacketStart = packetStart 273 | } 274 | } 275 | 276 | switch { 277 | case lastValidPacketStart != -1: 278 | // If there was at least one intra frame in the range scanned above, 279 | // our search is over. Jump back to the packet and decode it again. 280 | d.bufferSeek(lastValidPacketStart) 281 | 282 | return d.decodePacket(typ) 283 | case foundPacketInRange: 284 | // If we hit the right range, but still found no intra frame, we have to increase the scanSpan. 285 | // This is done exponentially to also handle video files with very few intra frames. 286 | scanSpan *= 2 287 | seekTime = firstPacketTime 288 | case !foundPacketWithPts: 289 | // If we didn't find any packet with a PTS, it probably means we reached 290 | // the end of the file. Estimate byteRate and curTime accordingly. 291 | byteRate = float64(seekPos-curPos) / (duration - curTime) 292 | curTime = duration 293 | } 294 | } 295 | 296 | return nil 297 | } 298 | 299 | // StartTime gets the PTS of the first packet of this type. 300 | // Returns PacketInvalidTS if packet of this packet type can not be found. 301 | func (d *Demux) StartTime(typ int) float64 { 302 | if d.startTime != PacketInvalidTS { 303 | return d.startTime 304 | } 305 | 306 | prevPos := d.buf.tell() 307 | prevStartCode := d.startCode 308 | 309 | // Find first video PTS 310 | d.Rewind() 311 | for { 312 | packet := d.Decode() 313 | if packet == nil { 314 | break 315 | } 316 | 317 | if packet.Type == typ { 318 | d.startTime = packet.Pts 319 | } 320 | 321 | if d.startTime != PacketInvalidTS { 322 | break 323 | } 324 | } 325 | 326 | d.bufferSeek(prevPos) 327 | d.startCode = prevStartCode 328 | 329 | return d.startTime 330 | } 331 | 332 | // Duration gets the duration for the specified packet type - i.e. the span between 333 | // the first PTS and the last PTS in the data source. 334 | func (d *Demux) Duration(typ int) float64 { 335 | fileSize := d.buf.Size() 336 | if d.duration != PacketInvalidTS && d.lastFileSize == fileSize { 337 | return d.duration 338 | } 339 | 340 | prevPos := d.buf.tell() 341 | prevStartCode := d.startCode 342 | 343 | // Find last video PTS. Start searching 64kb from the end and go further back if needed. 344 | startRange := 64 * 1024 345 | maxRange := 4096 * 1024 346 | 347 | for r := startRange; r <= maxRange; r *= 2 { 348 | seekPos := fileSize - r 349 | if seekPos < 0 { 350 | seekPos = 0 351 | r = maxRange // make sure to bail after this round 352 | } 353 | d.bufferSeek(seekPos) 354 | d.currentPacket.length = 0 355 | 356 | lastPts := float64(PacketInvalidTS) 357 | for { 358 | packet := d.Decode() 359 | if packet == nil { 360 | break 361 | } 362 | 363 | if packet.Pts != PacketInvalidTS && packet.Type == typ { 364 | lastPts = packet.Pts 365 | } 366 | } 367 | 368 | if lastPts != PacketInvalidTS { 369 | d.duration = lastPts - d.StartTime(typ) 370 | 371 | break 372 | } 373 | } 374 | 375 | d.bufferSeek(prevPos) 376 | d.startCode = prevStartCode 377 | d.lastFileSize = fileSize 378 | 379 | return d.duration 380 | } 381 | 382 | // Decode decodes and returns the next packet. 383 | func (d *Demux) Decode() *Packet { 384 | if !d.HasHeaders() { 385 | return nil 386 | } 387 | 388 | if d.currentPacket.length != 0 { 389 | bitsTillNextPacket := d.currentPacket.length << 3 390 | if !d.buf.has(bitsTillNextPacket) { 391 | return nil 392 | } 393 | 394 | d.buf.skip(bitsTillNextPacket) 395 | d.currentPacket.length = 0 396 | } 397 | 398 | // pending packet waiting for data? 399 | if d.nextPacket.length != 0 { 400 | return d.packet() 401 | } 402 | 403 | // pending packet waiting for header? 404 | if d.startCode != -1 { 405 | return d.decodePacket(d.startCode) 406 | } 407 | 408 | for { 409 | d.startCode = d.buf.nextStartCode() 410 | if d.startCode == PacketVideo1 || d.startCode == PacketPrivate || 411 | (d.startCode >= PacketAudio1 && d.startCode <= PacketAudio4) { 412 | return d.decodePacket(d.startCode) 413 | } 414 | 415 | if d.startCode == -1 { 416 | break 417 | } 418 | } 419 | 420 | return nil 421 | } 422 | 423 | func (d *Demux) bufferSeek(pos int) { 424 | d.buf.seek(pos) 425 | d.currentPacket.length = 0 426 | d.nextPacket.length = 0 427 | d.startCode = -1 428 | } 429 | 430 | func (d *Demux) decodeTime() float64 { 431 | clock := d.buf.read(3) << 30 432 | d.buf.skip(1) 433 | clock |= d.buf.read(15) << 15 434 | d.buf.skip(1) 435 | clock |= d.buf.read(15) 436 | d.buf.skip(1) 437 | 438 | return float64(clock) / 90000.0 439 | } 440 | 441 | func (d *Demux) decodePacket(typ int) *Packet { 442 | if !d.buf.has(16 << 3) { 443 | return nil 444 | } 445 | 446 | d.startCode = -1 447 | 448 | d.nextPacket.Type = typ 449 | d.nextPacket.length = d.buf.read(16) 450 | d.nextPacket.length -= d.buf.skipBytes(0xff) // stuffing 451 | 452 | // skip P-STD 453 | if d.buf.read(2) == 0x01 { 454 | d.buf.skip(16) 455 | d.nextPacket.length -= 2 456 | } 457 | 458 | ptsDtsMarker := d.buf.read(2) 459 | switch { 460 | case ptsDtsMarker == 0x03: 461 | d.nextPacket.Pts = d.decodeTime() 462 | d.lastDecodedPts = d.nextPacket.Pts 463 | d.buf.skip(40) // skip DTS 464 | d.nextPacket.length -= 10 465 | case ptsDtsMarker == 0x02: 466 | d.nextPacket.Pts = d.decodeTime() 467 | d.lastDecodedPts = d.nextPacket.Pts 468 | d.nextPacket.length -= 5 469 | case ptsDtsMarker == 0x00: 470 | d.nextPacket.Pts = PacketInvalidTS 471 | d.buf.skip(4) 472 | d.nextPacket.length -= 1 473 | default: 474 | return nil // invalid 475 | } 476 | 477 | return d.packet() 478 | } 479 | 480 | func (d *Demux) packet() *Packet { 481 | if !d.buf.has(d.nextPacket.length << 3) { 482 | return nil 483 | } 484 | 485 | index := d.buf.Index() 486 | d.currentPacket.Data = d.buf.Bytes()[index : index+d.nextPacket.length : index+d.nextPacket.length] 487 | d.currentPacket.Type = d.nextPacket.Type 488 | d.currentPacket.Pts = d.nextPacket.Pts 489 | 490 | d.currentPacket.length = d.nextPacket.length 491 | d.nextPacket.length = 0 492 | 493 | return &d.currentPacket 494 | } 495 | 496 | const ( 497 | startPack = 0xBA 498 | startEnd = 0xB9 499 | startSystem = 0xBB 500 | ) 501 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/gen2brain/mpeg 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /mpeg.go: -------------------------------------------------------------------------------- 1 | // Package mpeg implements MPEG-1 Video decoder, MP2 Audio decoder and MPEG-PS demuxer. 2 | // 3 | // This library provides several interfaces to demux and decode MPEG video and audio data. 4 | // A high-level MPEG API combines the demuxer, video and audio decoders in an easy-to-use wrapper. 5 | // 6 | // With the high-level interface you have two options to decode video and audio: 7 | // 8 | // 1. Decode() and just hand over the delta time since the last call. 9 | // It will decode everything needed and call your callbacks (specified through 10 | // Set{Video|Audio}Callback()) any number of times. 11 | // 12 | // 2. Use DecodeVideo() and DecodeAudio() to decode exactly one frame of video or audio data at a time. 13 | // How you handle the synchronization of both streams is up to you. 14 | // 15 | // If you only want to decode video *or* audio through these functions, you should 16 | // disable the other stream (Set{Video|Audio}Enabled(false)) 17 | // 18 | // Video data is decoded into a struct with all 3 planes (Y, Cb, Cr) stored in separate buffers, 19 | // you can get image.YCbCr via YCbCr() function. You can either convert to image.RGBA on the CPU (slow) 20 | // via the RGBA() function or do it on the GPU with the following matrix: 21 | // 22 | // mat4 bt601 = mat4( 23 | // 1.16438, 0.00000, 1.59603, -0.87079, 24 | // 1.16438, -0.39176, -0.81297, 0.52959, 25 | // 1.16438, 2.01723, 0.00000, -1.08139, 26 | // 0, 0, 0, 1 27 | // ); 28 | // 29 | // gl_FragColor = vec4(y, cb, cr, 1.0) * bt601; 30 | // 31 | // Audio data is decoded into a struct with separate []float32 slices for left and right channel, 32 | // and with a single []float32 slice with the samples for the left and right channel interleaved. 33 | // You can convert interleaved samples to byte slice via the Bytes() function. 34 | // 35 | // There should be no need to use the lower level Demux, Video and Audio, if all you want to do is 36 | // read/decode an MPEG-PS file. However, if you get raw mpeg1video data or raw mp2 audio data from a different source, 37 | // these functions can be used to decode the raw data directly. Similarly, if you only want to analyze an MPEG-PS file 38 | // or extract raw video or audio packets from it, you can use the Demux. 39 | package mpeg 40 | 41 | import ( 42 | "bytes" 43 | "errors" 44 | "io" 45 | "time" 46 | ) 47 | 48 | // VideoFunc callback function. 49 | type VideoFunc func(mpeg *MPEG, frame *Frame) 50 | 51 | // AudioFunc callback function. 52 | type AudioFunc func(mpeg *MPEG, samples *Samples) 53 | 54 | // ErrInvalidMPEG is the error returned when the reader is not a valid MPEG Program Stream. 55 | var ErrInvalidMPEG = errors.New("invalid MPEG-PS") 56 | 57 | // MPEG is high-level interface implementation. 58 | type MPEG struct { 59 | demux *Demux 60 | time float64 61 | 62 | loop bool 63 | hasEnded bool 64 | hasDecoders bool 65 | 66 | videoEnabled bool 67 | videoPacketType int 68 | videoBuffer *Buffer 69 | videoDecoder *Video 70 | 71 | audioEnabled bool 72 | audioPacketType int 73 | audioStreamIndex int 74 | audioLeadTime float64 75 | audioBuffer *Buffer 76 | audioDecoder *Audio 77 | 78 | done chan bool 79 | 80 | videoCallback VideoFunc 81 | audioCallback AudioFunc 82 | } 83 | 84 | // New creates a new MPEG instance. 85 | func New(r io.Reader) (*MPEG, error) { 86 | m := &MPEG{} 87 | 88 | buf, err := NewBuffer(r) 89 | if err != nil { 90 | return nil, err 91 | } 92 | 93 | buf.SetLoadCallback(buf.LoadReaderCallback) 94 | 95 | if !buf.has(32) { 96 | return nil, ErrInvalidMPEG 97 | } 98 | if !bytes.Equal([]byte{0x00, 0x00, 0x01, 0xBA}, buf.Bytes()[0:4]) { 99 | return nil, ErrInvalidMPEG 100 | } 101 | buf.Rewind() 102 | 103 | m.demux, err = NewDemux(buf) 104 | if err != nil { 105 | return nil, err 106 | } 107 | 108 | m.done = make(chan bool, 1) 109 | 110 | m.videoEnabled = true 111 | m.audioEnabled = true 112 | m.initDecoders() 113 | 114 | return m, nil 115 | } 116 | 117 | // HasHeaders checks whether we have headers on all available streams, and if we can accurately 118 | // report the number of video/audio streams, video dimensions, framerate and audio samplerate. 119 | func (m *MPEG) HasHeaders() bool { 120 | if !m.demux.HasHeaders() { 121 | return false 122 | } 123 | 124 | if !m.initDecoders() { 125 | return false 126 | } 127 | 128 | if (m.videoDecoder != nil && !m.videoDecoder.HasHeader()) || (m.audioDecoder != nil && !m.audioDecoder.HasHeader()) { 129 | return false 130 | } 131 | 132 | return true 133 | } 134 | 135 | // Done returns done channel. 136 | func (m *MPEG) Done() chan bool { 137 | return m.done 138 | } 139 | 140 | // Video returns video decoder. 141 | func (m *MPEG) Video() *Video { 142 | return m.videoDecoder 143 | } 144 | 145 | // SetVideoCallback sets a video callback. 146 | func (m *MPEG) SetVideoCallback(callback VideoFunc) { 147 | m.videoCallback = callback 148 | } 149 | 150 | // VideoEnabled checks whether video decoding is enabled. 151 | func (m *MPEG) VideoEnabled() bool { 152 | return m.videoEnabled 153 | } 154 | 155 | // SetVideoEnabled sets whether video decoding is enabled. 156 | func (m *MPEG) SetVideoEnabled(enabled bool) { 157 | m.videoEnabled = enabled 158 | 159 | if !enabled { 160 | m.videoPacketType = 0 161 | 162 | return 163 | } 164 | 165 | if m.initDecoders() && m.videoDecoder != nil { 166 | m.videoPacketType = PacketVideo1 167 | } else { 168 | m.videoPacketType = 0 169 | } 170 | } 171 | 172 | // NumVideoStreams returns the number of video streams (0--1) reported in the system header. 173 | func (m *MPEG) NumVideoStreams() int { 174 | return m.demux.NumVideoStreams() 175 | } 176 | 177 | // Width returns the display width of the video stream. 178 | func (m *MPEG) Width() int { 179 | if m.initDecoders() && m.videoDecoder != nil { 180 | return m.videoDecoder.Width() 181 | } 182 | 183 | return 0 184 | } 185 | 186 | // Height returns the display height of the video stream. 187 | func (m *MPEG) Height() int { 188 | if m.initDecoders() && m.videoDecoder != nil { 189 | return m.videoDecoder.Height() 190 | } 191 | 192 | return 0 193 | } 194 | 195 | // Framerate returns the framerate of the video stream in frames per second. 196 | func (m *MPEG) Framerate() float64 { 197 | if m.initDecoders() && m.videoDecoder != nil { 198 | return m.videoDecoder.Framerate() 199 | } 200 | 201 | return 0 202 | } 203 | 204 | // Audio returns video decoder. 205 | func (m *MPEG) Audio() *Audio { 206 | return m.audioDecoder 207 | } 208 | 209 | // AudioFormat returns audio format. 210 | func (m *MPEG) AudioFormat() AudioFormat { 211 | return m.audioDecoder.format 212 | } 213 | 214 | // SetAudioFormat sets audio format. 215 | func (m *MPEG) SetAudioFormat(format AudioFormat) { 216 | m.audioDecoder.format = format 217 | m.audioDecoder.samples.format = format 218 | } 219 | 220 | // SetAudioCallback sets a audio callback. 221 | func (m *MPEG) SetAudioCallback(callback AudioFunc) { 222 | m.audioCallback = callback 223 | } 224 | 225 | // AudioEnabled checks whether audio decoding is enabled. 226 | func (m *MPEG) AudioEnabled() bool { 227 | return m.audioEnabled 228 | } 229 | 230 | // SetAudioEnabled sets whether audio decoding is enabled. 231 | func (m *MPEG) SetAudioEnabled(enabled bool) { 232 | m.audioEnabled = enabled 233 | if !enabled { 234 | m.audioPacketType = 0 235 | 236 | return 237 | } 238 | 239 | if m.initDecoders() && m.audioDecoder != nil { 240 | m.audioPacketType = PacketAudio1 + m.audioStreamIndex 241 | } else { 242 | m.audioPacketType = 0 243 | } 244 | } 245 | 246 | // NumAudioStreams returns the number of audio streams (0--4) reported in the system header. 247 | func (m *MPEG) NumAudioStreams() int { 248 | return m.demux.NumAudioStreams() 249 | } 250 | 251 | // SetAudioStream sets the desired audio stream (0--3). Default 0. 252 | func (m *MPEG) SetAudioStream(streamIndex int) { 253 | if streamIndex < 0 || streamIndex > 3 { 254 | return 255 | } 256 | m.audioStreamIndex = streamIndex 257 | 258 | // Set the correct audio_packet_type 259 | m.SetAudioEnabled(m.audioEnabled) 260 | } 261 | 262 | // Samplerate returns the samplerate of the audio stream in samples per second. 263 | func (m *MPEG) Samplerate() int { 264 | if m.initDecoders() && m.audioDecoder != nil { 265 | return m.audioDecoder.Samplerate() 266 | } 267 | 268 | return 0 269 | } 270 | 271 | // Channels returns the number of channels. 272 | func (m *MPEG) Channels() int { 273 | if m.initDecoders() && m.audioDecoder != nil { 274 | return m.audioDecoder.Channels() 275 | } 276 | 277 | return 0 278 | } 279 | 280 | // AudioLeadTime returns the audio lead time in seconds - the time in which audio samples 281 | // are decoded in advance (or behind) the video decode time. 282 | func (m *MPEG) AudioLeadTime() time.Duration { 283 | return time.Duration(m.audioLeadTime * float64(time.Second)) 284 | } 285 | 286 | // SetAudioLeadTime sets the audio lead time in seconds. Typically, this 287 | // should be set to the duration of the buffer of the audio API that you use 288 | // for output. E.g. for SDL2: (SDL_AudioSpec.samples / samplerate). 289 | func (m *MPEG) SetAudioLeadTime(leadTime time.Duration) { 290 | m.audioLeadTime = leadTime.Seconds() 291 | } 292 | 293 | // Time returns the current internal time in seconds. 294 | func (m *MPEG) Time() time.Duration { 295 | return time.Duration(m.time * float64(time.Second)) 296 | } 297 | 298 | // Duration returns the video duration of the underlying source. 299 | func (m *MPEG) Duration() time.Duration { 300 | return time.Duration(m.demux.Duration(PacketVideo1) * float64(time.Second)) 301 | } 302 | 303 | // Rewind rewinds all buffers back to the beginning. 304 | func (m *MPEG) Rewind() { 305 | if m.videoDecoder != nil { 306 | m.videoDecoder.Rewind() 307 | } 308 | 309 | if m.audioDecoder != nil { 310 | m.audioDecoder.Rewind() 311 | } 312 | 313 | m.demux.Rewind() 314 | m.time = 0 315 | } 316 | 317 | // Loop returns looping. 318 | func (m *MPEG) Loop() bool { 319 | return m.loop 320 | } 321 | 322 | // SetLoop sets looping. 323 | func (m *MPEG) SetLoop(loop bool) { 324 | m.loop = loop 325 | } 326 | 327 | // HasEnded checks whether the file has ended. 328 | // If looping is enabled, this will always return false. 329 | func (m *MPEG) HasEnded() bool { 330 | return m.hasEnded 331 | } 332 | 333 | // Decode advances the internal timer by seconds and decode video/audio up to this time. 334 | // This will call the video_decode_callback and audio_decode_callback any number of times. 335 | // A frame-skip is not implemented, i.e. everything up to current time will be decoded. 336 | func (m *MPEG) Decode(tick time.Duration) { 337 | if !m.initDecoders() { 338 | return 339 | } 340 | 341 | decodeVideo := m.videoCallback != nil && m.videoPacketType != 0 342 | decodeAudio := m.audioCallback != nil && m.audioPacketType != 0 343 | 344 | if !decodeVideo && !decodeAudio { 345 | // Nothing to do here 346 | return 347 | } 348 | 349 | didDecode := false 350 | decodeVideoFailed := false 351 | decodeAudioFailed := false 352 | 353 | videoTargetTime := m.time + tick.Seconds() 354 | audioTargetTime := m.time + tick.Seconds() + m.audioLeadTime 355 | 356 | for { 357 | didDecode = false 358 | 359 | if decodeVideo && m.videoDecoder.Time() < videoTargetTime { 360 | frame := m.videoDecoder.Decode() 361 | if frame != nil { 362 | m.videoCallback(m, frame) 363 | didDecode = true 364 | } else { 365 | decodeVideoFailed = true 366 | } 367 | } 368 | 369 | if decodeAudio && m.audioDecoder.Time() < audioTargetTime { 370 | samples := m.audioDecoder.Decode() 371 | if samples != nil { 372 | m.audioCallback(m, samples) 373 | didDecode = true 374 | } else { 375 | decodeAudioFailed = true 376 | } 377 | } 378 | 379 | if !didDecode { 380 | break 381 | } 382 | } 383 | 384 | if (!decodeVideo || decodeVideoFailed) && (!decodeAudio || decodeAudioFailed) && m.demux.HasEnded() { 385 | m.handleEnd() 386 | 387 | return 388 | } 389 | 390 | m.time += tick.Seconds() 391 | } 392 | 393 | // DecodeVideo decodes and returns one video frame. Returns nil if no frame could be decoded 394 | // (either because the source ended or data is corrupt). If you only want to decode video, you should 395 | // disable audio via SetAudioEnabled(). The returned Frame is valid until the next call to DecodeVideo(). 396 | func (m *MPEG) DecodeVideo() *Frame { 397 | if !m.initDecoders() { 398 | return nil 399 | } 400 | 401 | if m.videoPacketType == 0 { 402 | return nil 403 | } 404 | 405 | frame := m.videoDecoder.Decode() 406 | if frame != nil { 407 | m.time = frame.Time 408 | } else if m.demux.HasEnded() { 409 | m.handleEnd() 410 | } 411 | 412 | return frame 413 | } 414 | 415 | // DecodeAudio decodes and returns one audio frame. Returns nil if no frame could be decoded 416 | // (either because the source ended or data is corrupt). If you only want to decode audio, you should 417 | // disable video via SetVideoEnabled(). The returned Samples is valid until the next call to DecodeAudio(). 418 | func (m *MPEG) DecodeAudio() *Samples { 419 | if !m.initDecoders() { 420 | return nil 421 | } 422 | 423 | if m.audioPacketType == 0 { 424 | return nil 425 | } 426 | 427 | samples := m.audioDecoder.Decode() 428 | if samples != nil { 429 | m.time = samples.Time 430 | } else if m.demux.HasEnded() { 431 | m.handleEnd() 432 | } 433 | 434 | return samples 435 | } 436 | 437 | // SeekFrame seeks, similar to Seek(), but will not call the VideoFunc callback, 438 | // AudioFunc callback or make any attempts to sync audio. 439 | // Returns the found frame or nil if no frame could be found. 440 | func (m *MPEG) SeekFrame(tm time.Duration, seekExact bool) *Frame { 441 | if !m.initDecoders() { 442 | return nil 443 | } 444 | 445 | if m.videoPacketType == 0 { 446 | return nil 447 | } 448 | 449 | typ := m.videoPacketType 450 | startTime := m.demux.StartTime(typ) 451 | duration := m.demux.Duration(typ) 452 | 453 | if tm.Seconds() < 0 { 454 | tm = 0 455 | } else if tm.Seconds() > duration { 456 | tm = time.Duration(duration * float64(time.Second)) 457 | } 458 | 459 | packet := m.demux.Seek(tm.Seconds(), typ, true) 460 | if packet == nil { 461 | return nil 462 | } 463 | 464 | // Disable writing to the audio buffer while decoding video 465 | prevAudioPacketType := m.audioPacketType 466 | m.audioPacketType = 0 467 | 468 | // Clear video buffer and decode the found packet 469 | m.videoDecoder.Rewind() 470 | m.videoDecoder.SetTime(packet.Pts - startTime) 471 | m.videoBuffer.Write(packet.Data) 472 | frame := m.videoDecoder.Decode() 473 | 474 | // If we want to seek to an exact frame, we have to decode all frames 475 | // on top of the intra frame we just jumped to. 476 | if seekExact { 477 | for frame != nil && frame.Time < tm.Seconds() { 478 | frame = m.videoDecoder.Decode() 479 | } 480 | } 481 | 482 | // Enable writing to the audio buffer again 483 | m.audioPacketType = prevAudioPacketType 484 | 485 | if frame != nil { 486 | m.time = frame.Time 487 | } 488 | 489 | m.hasEnded = false 490 | 491 | return frame 492 | } 493 | 494 | // Seek seeks to the specified time, clamped between 0 -- duration. This can only be 495 | // used when the underlying Buffer is seekable. 496 | // If seekExact is true this will seek to the exact time, otherwise it will 497 | // seek to the last intra frame just before the desired time. Exact seeking can 498 | // be slow, because all frames up to the seeked one have to be decoded on top of 499 | // the previous intra frame. 500 | // If seeking succeeds, this function will call the VideoFunc callback 501 | // exactly once with the target frame. If audio is enabled, it will also call 502 | // the AudioFunc callback any number of times, until the audioLeadTime is satisfied. 503 | // Returns true if seeking succeeded or false if no frame could be found. 504 | func (m *MPEG) Seek(tm time.Duration, seekExact bool) bool { 505 | frame := m.SeekFrame(tm, seekExact) 506 | 507 | if frame == nil { 508 | return false 509 | } 510 | 511 | if m.videoCallback != nil { 512 | m.videoCallback(m, frame) 513 | } 514 | 515 | // If audio is not enabled we are done here. 516 | if m.audioPacketType == 0 { 517 | return true 518 | } 519 | 520 | // Sync up Audio. This demuxes more packets until the first audio packet 521 | // with a PTS greater than the current time is found. Decode() is then 522 | // called to decode enough audio data to satisfy the audioLeadTime. 523 | 524 | startTime := m.demux.StartTime(m.videoPacketType) 525 | m.audioDecoder.Rewind() 526 | 527 | for { 528 | packet := m.demux.Decode() 529 | if packet == nil { 530 | break 531 | } 532 | 533 | if packet.Type == m.videoPacketType { 534 | m.videoBuffer.Write(packet.Data) 535 | } else if packet.Type == m.audioPacketType && packet.Pts-startTime > m.time { 536 | m.audioDecoder.SetTime(packet.Pts - startTime) 537 | m.audioBuffer.Write(packet.Data) 538 | 539 | // Disable writing to the audio buffer while decoding video 540 | prevAudioPacketType := m.audioPacketType 541 | m.audioPacketType = 0 542 | 543 | m.Decode(0) 544 | 545 | // Enable writing to the audio buffer again 546 | m.audioPacketType = prevAudioPacketType 547 | 548 | // Decode audio 549 | m.Decode(0) 550 | 551 | break 552 | } 553 | } 554 | 555 | return true 556 | } 557 | 558 | func (m *MPEG) initDecoders() bool { 559 | if m.hasDecoders { 560 | return true 561 | } 562 | 563 | if !m.demux.HasHeaders() { 564 | return false 565 | } 566 | 567 | var err error 568 | if m.demux.NumVideoStreams() > 0 { 569 | if m.videoEnabled { 570 | m.videoPacketType = PacketVideo1 571 | } 572 | 573 | m.videoBuffer, err = NewBuffer(nil) 574 | if err != nil { 575 | return false 576 | } 577 | 578 | m.videoBuffer.SetLoadCallback(m.readVideoPacket) 579 | } 580 | 581 | if m.demux.NumAudioStreams() > 0 { 582 | if m.audioEnabled { 583 | m.audioPacketType = PacketAudio1 + m.audioStreamIndex 584 | } 585 | 586 | m.audioBuffer, err = NewBuffer(nil) 587 | if err != nil { 588 | return false 589 | } 590 | 591 | m.audioBuffer.SetLoadCallback(m.readAudioPacket) 592 | } 593 | 594 | if m.videoBuffer != nil { 595 | m.videoDecoder = NewVideo(m.videoBuffer) 596 | } 597 | 598 | if m.audioBuffer != nil { 599 | m.audioDecoder = NewAudio(m.audioBuffer) 600 | } 601 | 602 | m.hasDecoders = true 603 | 604 | return true 605 | } 606 | 607 | func (m *MPEG) handleEnd() { 608 | if m.loop { 609 | m.Rewind() 610 | } else { 611 | m.hasEnded = true 612 | m.done <- true 613 | } 614 | } 615 | 616 | func (m *MPEG) readVideoPacket(buffer *Buffer) { 617 | m.readPackets(m.videoPacketType) 618 | } 619 | 620 | func (m *MPEG) readAudioPacket(buffer *Buffer) { 621 | m.readPackets(m.audioPacketType) 622 | } 623 | 624 | func (m *MPEG) readPackets(requestedType int) { 625 | for { 626 | packet := m.demux.Decode() 627 | if packet == nil { 628 | break 629 | } 630 | 631 | if packet.Type == m.videoPacketType { 632 | m.videoBuffer.Write(packet.Data) 633 | } else if packet.Type == m.audioPacketType { 634 | m.audioBuffer.Write(packet.Data) 635 | } 636 | 637 | if packet.Type == requestedType { 638 | return 639 | } 640 | } 641 | 642 | if m.demux.HasEnded() { 643 | if m.videoBuffer != nil { 644 | m.videoBuffer.SignalEnd() 645 | } 646 | 647 | if m.audioBuffer != nil { 648 | m.audioBuffer.SignalEnd() 649 | } 650 | } 651 | } 652 | -------------------------------------------------------------------------------- /mpeg_test.go: -------------------------------------------------------------------------------- 1 | package mpeg_test 2 | 3 | import ( 4 | "bytes" 5 | _ "embed" 6 | "testing" 7 | "time" 8 | 9 | "github.com/gen2brain/mpeg" 10 | ) 11 | 12 | //go:embed testdata/test.mp2 13 | var testMp2 []byte 14 | 15 | //go:embed testdata/test.mpeg1video 16 | var testMpeg1video []byte 17 | 18 | //go:embed testdata/test.mpg 19 | var testMpg []byte 20 | 21 | func TestBuffer(t *testing.T) { 22 | buffer, err := mpeg.NewBuffer(bytes.NewReader(testMpg)) 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | 27 | buffer.SetLoadCallback(buffer.LoadReaderCallback) 28 | 29 | if !buffer.Seekable() { 30 | t.Error("Seekable: not seekable") 31 | } 32 | 33 | if buffer.Size() != 380932 { 34 | t.Errorf("Size: got %d, want %d", buffer.Size(), 380932) 35 | } 36 | } 37 | 38 | func TestDemux(t *testing.T) { 39 | buf, err := mpeg.NewBuffer(bytes.NewReader(testMpg)) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | 44 | buf.SetLoadCallback(buf.LoadReaderCallback) 45 | 46 | demux, err := mpeg.NewDemux(buf) 47 | if err != nil { 48 | t.Fatal(err) 49 | } 50 | 51 | if !demux.HasHeaders() { 52 | t.Error("HasHeaders: no headers") 53 | } 54 | 55 | if demux.NumAudioStreams() != 1 { 56 | t.Errorf("NumAudioStreams: got %d, want %d", demux.NumAudioStreams(), 1) 57 | } 58 | 59 | if demux.NumVideoStreams() != 1 { 60 | t.Errorf("NumVideoStreams: got %d, want %d", demux.NumVideoStreams(), 1) 61 | } 62 | 63 | if int(demux.Duration(mpeg.PacketVideo1)) != 9 { 64 | t.Errorf("Duration: got %d, want %d", int(demux.Duration(mpeg.PacketVideo1)), 9) 65 | } 66 | 67 | packet := demux.Decode() 68 | if packet == nil { 69 | t.Fatal("Decode: packet is nil") 70 | } 71 | 72 | if packet.Type != mpeg.PacketVideo1 { 73 | t.Errorf("Type: got %d, want %d", packet.Type, mpeg.PacketVideo1) 74 | } 75 | } 76 | 77 | func TestAudio(t *testing.T) { 78 | buf, err := mpeg.NewBuffer(bytes.NewReader(testMp2)) 79 | if err != nil { 80 | t.Fatal(err) 81 | } 82 | 83 | buf.SetLoadCallback(buf.LoadReaderCallback) 84 | 85 | audio := mpeg.NewAudio(buf) 86 | if !audio.HasHeader() { 87 | t.Error("HasHeader: no header") 88 | } 89 | 90 | if audio.Samplerate() != 44100 { 91 | t.Errorf("Samplerate: got %d, want %d", audio.Samplerate(), 44100) 92 | } 93 | 94 | if audio.Channels() != 1 { 95 | t.Errorf("Channels: got %d, want %d", audio.Channels(), 1) 96 | } 97 | 98 | audio.Rewind() 99 | samples := audio.Decode() 100 | 101 | if samples == nil { 102 | t.Error("Decode: samples is nil") 103 | } 104 | } 105 | 106 | func TestVideo(t *testing.T) { 107 | buf, err := mpeg.NewBuffer(bytes.NewReader(testMpeg1video)) 108 | if err != nil { 109 | t.Fatal(err) 110 | } 111 | 112 | buf.SetLoadCallback(buf.LoadReaderCallback) 113 | 114 | video := mpeg.NewVideo(buf) 115 | if !video.HasHeader() { 116 | t.Error("HasHeader: no header") 117 | } 118 | 119 | if video.Width() != 160 { 120 | t.Errorf("Width: got %d, want %d", video.Width(), 120) 121 | } 122 | 123 | if video.Height() != 120 { 124 | t.Errorf("Height: got %d, want %d", video.Height(), 120) 125 | } 126 | 127 | if video.Framerate() != 30.0 { 128 | t.Errorf("Framerate: got %f, want %f", video.Framerate(), 30.0) 129 | } 130 | 131 | frame := video.Decode() 132 | if frame == nil { 133 | t.Fatal("Decode: frame is nil") 134 | } 135 | 136 | if frame.Width != video.Width() { 137 | t.Errorf("Width: got %d, want %d", frame.Width, video.Width()) 138 | } 139 | 140 | if len(frame.Y.Data) != 20480 { 141 | t.Errorf("Y: got %d, want %d", len(frame.Y.Data), 20480) 142 | } 143 | 144 | if len(frame.Cb.Data) != len(frame.Y.Data)/4 { 145 | t.Errorf("Cb: got %d, want %d", len(frame.Cb.Data), len(frame.Y.Data)/4) 146 | } 147 | } 148 | 149 | func TestMpeg(t *testing.T) { 150 | mpg, err := mpeg.New(bytes.NewReader(testMpg)) 151 | if err != nil { 152 | t.Fatal(err) 153 | } 154 | 155 | if !mpg.HasHeaders() { 156 | t.Error("HasHeaders: no headers") 157 | } 158 | 159 | if mpg.NumAudioStreams() != 1 { 160 | t.Errorf("NumAudioStreams: got %d, want %d", mpg.NumAudioStreams(), 1) 161 | } 162 | 163 | if mpg.NumVideoStreams() != 1 { 164 | t.Errorf("NumVideoStreams: got %d, want %d", mpg.NumVideoStreams(), 1) 165 | } 166 | 167 | if mpg.Width() != 160 { 168 | t.Errorf("Width: got %d, want %d", mpg.Width(), 120) 169 | } 170 | 171 | if mpg.Height() != 120 { 172 | t.Errorf("Height: got %d, want %d", mpg.Height(), 120) 173 | } 174 | 175 | if mpg.Framerate() != 30.0 { 176 | t.Errorf("Framerate: got %f, want %f", mpg.Framerate(), 30.0) 177 | } 178 | 179 | mpg.SetAudioStream(0) 180 | mpg.SetAudioEnabled(true) 181 | if !mpg.AudioEnabled() { 182 | t.Errorf("AudioEnabled: got %v, want %v", mpg.AudioEnabled(), true) 183 | } 184 | 185 | mpg.SetVideoEnabled(true) 186 | if !mpg.VideoEnabled() { 187 | t.Errorf("VideoEnabled: got %v, want %v", mpg.VideoEnabled(), true) 188 | } 189 | 190 | if mpg.Samplerate() != 44100 { 191 | t.Errorf("Samplerate: got %d, want %d", mpg.Samplerate(), 44100) 192 | } 193 | 194 | if mpg.Channels() != 1 { 195 | t.Errorf("Channels: got %d, want %d", mpg.Channels(), 1) 196 | } 197 | 198 | mpg.SetAudioLeadTime(1 * time.Second) 199 | if mpg.AudioLeadTime().Seconds() != 1 { 200 | t.Errorf("AudioLeadTime: got %s, want %f", mpg.AudioLeadTime(), 1.0) 201 | } 202 | 203 | if int(mpg.Duration().Seconds()) != 9 { 204 | t.Errorf("Duration: got %d, want %d", int(mpg.Duration()), 9) 205 | } 206 | 207 | mpg.Rewind() 208 | mpg.SetLoop(false) 209 | if mpg.Loop() { 210 | t.Errorf("Loop: got %v, want %v", mpg.Loop(), false) 211 | } 212 | 213 | mpg.SetAudioEnabled(false) 214 | mpg.SetVideoEnabled(true) 215 | frame := mpg.DecodeVideo() 216 | if frame == nil { 217 | t.Fatal("DecodeVideo: frame is nil") 218 | } 219 | 220 | if frame.Width != mpg.Width() { 221 | t.Errorf("Width: got %d, want %d", frame.Width, mpg.Width()) 222 | } 223 | 224 | if len(frame.Y.Data) != 20480 { 225 | t.Errorf("Y: got %d, want %d", len(frame.Y.Data), 20480) 226 | } 227 | 228 | if len(frame.Cb.Data) != len(frame.Y.Data)/4 { 229 | t.Errorf("Cb: got %d, want %d", len(frame.Cb.Data), len(frame.Y.Data)/4) 230 | } 231 | 232 | mpg.SetAudioEnabled(true) 233 | mpg.SetVideoEnabled(false) 234 | samples := mpg.DecodeAudio() 235 | if samples == nil { 236 | t.Fatal("DecodeAudio: samples is nil") 237 | } 238 | 239 | if len(samples.Bytes()) != len(samples.Interleaved)*4 { 240 | t.Errorf("bytes: got %d, want %d", len(samples.Bytes()), len(samples.Interleaved)*4) 241 | } 242 | 243 | mpg.SetAudioEnabled(true) 244 | mpg.SetVideoEnabled(true) 245 | ret := mpg.Seek(1, false) 246 | if !ret { 247 | t.Fatal("Seek: returned false") 248 | } 249 | 250 | frame = mpg.SeekFrame(1*time.Second, true) 251 | if frame == nil { 252 | t.Fatal("SeekFrame: frame is nil") 253 | } 254 | 255 | frame = mpg.SeekFrame(100*time.Second, true) 256 | if frame != nil { 257 | t.Fatal("SeekFrame: expected nil frame") 258 | } 259 | 260 | mpg.SetAudioCallback(func(m *mpeg.MPEG, s *mpeg.Samples) {}) 261 | mpg.SetVideoCallback(func(m *mpeg.MPEG, f *mpeg.Frame) {}) 262 | mpg.Decode(1 * time.Second) 263 | } 264 | 265 | func BenchmarkDecodeVideo(b *testing.B) { 266 | mpg, err := mpeg.New(bytes.NewReader(testMpg)) 267 | if err != nil { 268 | b.Fatal(err) 269 | } 270 | 271 | mpg.SetLoop(true) 272 | mpg.SetAudioEnabled(false) 273 | 274 | b.ReportAllocs() 275 | for i := 0; i < b.N; i++ { 276 | mpg.DecodeVideo() 277 | } 278 | } 279 | 280 | func BenchmarkDecodeAudio(b *testing.B) { 281 | mpg, err := mpeg.New(bytes.NewReader(testMpg)) 282 | if err != nil { 283 | b.Fatal(err) 284 | } 285 | 286 | mpg.SetLoop(true) 287 | mpg.SetVideoEnabled(false) 288 | 289 | b.ReportAllocs() 290 | for i := 0; i < b.N; i++ { 291 | mpg.DecodeAudio() 292 | } 293 | } 294 | 295 | func BenchmarkRGBA(b *testing.B) { 296 | mpg, err := mpeg.New(bytes.NewReader(testMpg)) 297 | if err != nil { 298 | b.Fatal(err) 299 | } 300 | 301 | frame := mpg.DecodeVideo() 302 | if frame == nil { 303 | b.Fatal("DecodeVideo: frame is nil") 304 | } 305 | 306 | b.ReportAllocs() 307 | for i := 0; i < b.N; i++ { 308 | frame.RGBA() 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /testdata/test.mp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gen2brain/mpeg/fcc3076074164e343053fef70d645f8aaa68bc79/testdata/test.mp2 -------------------------------------------------------------------------------- /testdata/test.mpeg1video: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gen2brain/mpeg/fcc3076074164e343053fef70d645f8aaa68bc79/testdata/test.mpeg1video -------------------------------------------------------------------------------- /testdata/test.mpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gen2brain/mpeg/fcc3076074164e343053fef70d645f8aaa68bc79/testdata/test.mpg -------------------------------------------------------------------------------- /video.go: -------------------------------------------------------------------------------- 1 | package mpeg 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | "image/draw" 7 | "unsafe" 8 | ) 9 | 10 | // Frame represents decoded video frame. 11 | type Frame struct { 12 | Time float64 13 | 14 | Width int 15 | Height int 16 | 17 | Y Plane 18 | Cb Plane 19 | Cr Plane 20 | 21 | imYCbCr image.YCbCr 22 | imRGBA image.RGBA 23 | } 24 | 25 | // YCbCr returns frame as image.YCbCr. 26 | func (f *Frame) YCbCr() *image.YCbCr { 27 | return &f.imYCbCr 28 | } 29 | 30 | // RGBA returns frame as image.RGBA. 31 | func (f *Frame) RGBA() *image.RGBA { 32 | b := f.imYCbCr.Bounds() 33 | draw.Draw(&f.imRGBA, b.Bounds(), &f.imYCbCr, b.Min, draw.Src) 34 | 35 | return &f.imRGBA 36 | } 37 | 38 | // Pixels returns frame as slice of color.RGBA. 39 | func (f *Frame) Pixels() []color.RGBA { 40 | img := f.RGBA() 41 | 42 | return unsafe.Slice((*color.RGBA)(unsafe.Pointer(&img.Pix[0])), len(img.Pix)/4) 43 | } 44 | 45 | // Plane represents decoded video plane. 46 | // The byte length of the data is width * height. Note that different planes have different sizes: 47 | // the Luma plane (Y) is double the size of each of the two Chroma planes (Cr, Cb) - i.e. 4 times the byte length. 48 | // Also note that the size of the plane does *not* denote the size of the displayed frame. 49 | // The sizes of planes are always rounded up to the nearest macroblock (16px). 50 | type Plane struct { 51 | Width int 52 | Height int 53 | Data []byte 54 | } 55 | 56 | // Video decodes MPEG-1 Video (mpeg1) data into raw YCrCb frames. 57 | type Video struct { 58 | aspectRatio float64 59 | frameRate float64 60 | time float64 61 | bitRate int 62 | framesDecoded int 63 | width int 64 | height int 65 | mbWidth int 66 | mbHeight int 67 | mbSize int 68 | 69 | lumaWidth int 70 | lumaHeight int 71 | 72 | chromaWidth int 73 | chromaHeight int 74 | 75 | startCode int 76 | pictureType int 77 | 78 | motionForward motion 79 | motionBackward motion 80 | 81 | hasSequenceHeader bool 82 | 83 | quantizerScale int 84 | sliceBegin bool 85 | macroblockAddress int 86 | 87 | mbRow int 88 | mbCol int 89 | 90 | macroblockType int 91 | macroblockIntra bool 92 | 93 | dcPredictor []int 94 | 95 | buf *Buffer 96 | 97 | frameCurrent Frame 98 | frameForward Frame 99 | frameBackward Frame 100 | 101 | blockData []int 102 | intraQuantMatrix []byte 103 | nonIntraQuantMatrix []byte 104 | 105 | hasReferenceFrame bool 106 | assumeNoBFrames bool 107 | } 108 | 109 | // NewVideo creates a video decoder with buffer as a source. 110 | func NewVideo(buf *Buffer) *Video { 111 | video := &Video{} 112 | video.buf = buf 113 | 114 | video.dcPredictor = make([]int, 3) 115 | video.blockData = make([]int, 64) 116 | video.intraQuantMatrix = make([]byte, 64) 117 | video.nonIntraQuantMatrix = make([]byte, 64) 118 | 119 | // Attempt to decode the sequence header 120 | video.startCode = video.buf.findStartCode(startSequence) 121 | if video.startCode != -1 { 122 | video.decodeSequenceHeader() 123 | } 124 | 125 | return video 126 | } 127 | 128 | // Buffer returns video buffer. 129 | func (v *Video) Buffer() *Buffer { 130 | return v.buf 131 | } 132 | 133 | // HasHeader checks whether a sequence header was found, and we can accurately report on 134 | // dimensions and framerate. 135 | func (v *Video) HasHeader() bool { 136 | if v.hasSequenceHeader { 137 | return true 138 | } 139 | 140 | if v.startCode != startSequence { 141 | v.startCode = v.buf.findStartCode(startSequence) 142 | } 143 | if v.startCode == -1 { 144 | return false 145 | } 146 | 147 | if !v.decodeSequenceHeader() { 148 | return false 149 | } 150 | 151 | return true 152 | } 153 | 154 | // Framerate returns the framerate in frames per second. 155 | func (v *Video) Framerate() float64 { 156 | if v.HasHeader() { 157 | return v.frameRate 158 | } 159 | 160 | return 0 161 | } 162 | 163 | // Width returns the display width. 164 | func (v *Video) Width() int { 165 | if v.HasHeader() { 166 | return v.width 167 | } 168 | 169 | return 0 170 | } 171 | 172 | // Height returns the display height. 173 | func (v *Video) Height() int { 174 | if v.HasHeader() { 175 | return v.height 176 | } 177 | 178 | return 0 179 | } 180 | 181 | // SetNoDelay sets "no delay" mode. When enabled, the decoder assumes that the video does 182 | // *not* contain any B-Frames. This is useful for reducing lag when streaming. 183 | func (v *Video) SetNoDelay(noDelay bool) { 184 | v.assumeNoBFrames = noDelay 185 | } 186 | 187 | // Time returns the current internal time in seconds. 188 | func (v *Video) Time() float64 { 189 | return v.time 190 | } 191 | 192 | // SetTime sets the current internal time in seconds. This is only useful when you 193 | // manipulate the underlying video buffer and want to enforce a correct timestamps. 194 | func (v *Video) SetTime(time float64) { 195 | v.framesDecoded = int(v.frameRate * v.time) 196 | v.time = time 197 | } 198 | 199 | // Rewind rewinds the internal buffer. 200 | func (v *Video) Rewind() { 201 | v.buf.Rewind() 202 | v.time = 0 203 | v.framesDecoded = 0 204 | v.hasReferenceFrame = false 205 | v.startCode = -1 206 | } 207 | 208 | // HasEnded checks whether the file has ended. This will be cleared on rewind. 209 | func (v *Video) HasEnded() bool { 210 | return v.buf.HasEnded() 211 | } 212 | 213 | // Decode decodes and returns one frame of video and advance the internal time by 1/framerate seconds. 214 | func (v *Video) Decode() *Frame { 215 | if !v.HasHeader() { 216 | return nil 217 | } 218 | 219 | var frame *Frame 220 | 221 | for { 222 | if v.startCode != startPicture { 223 | v.startCode = v.buf.findStartCode(startPicture) 224 | 225 | if v.startCode == -1 { 226 | // If we reached the end of the file and the previously decoded 227 | // frame was a reference frame, we still have to return it. 228 | if v.hasReferenceFrame && !v.assumeNoBFrames && v.buf.HasEnded() && 229 | (v.pictureType == pictureTypeIntra || v.pictureType == pictureTypePredictive) { 230 | v.hasReferenceFrame = false 231 | frame = &v.frameBackward 232 | 233 | break 234 | } 235 | 236 | return nil 237 | } 238 | } 239 | 240 | // Make sure we have a full picture in the buffer before attempting to 241 | // decode it. Sadly, this can only be done by seeking for the start code 242 | // of the next picture. Also, if we didn't find the start code for the 243 | // next picture, but the source has ended, we assume that this last 244 | // picture is in the buffer. 245 | if v.buf.hasStartCode(startPicture) == -1 && !v.buf.HasEnded() { 246 | return nil 247 | } 248 | v.buf.discardReadBytes() 249 | 250 | v.decodePicture() 251 | 252 | switch { 253 | case v.assumeNoBFrames: 254 | frame = &v.frameBackward 255 | case v.pictureType == pictureTypeB: 256 | frame = &v.frameCurrent 257 | case v.hasReferenceFrame: 258 | frame = &v.frameForward 259 | default: 260 | v.hasReferenceFrame = true 261 | } 262 | 263 | if frame != nil { 264 | break 265 | } 266 | } 267 | 268 | frame.Time = v.time 269 | v.framesDecoded++ 270 | v.time = float64(v.framesDecoded) / v.frameRate 271 | 272 | return frame 273 | } 274 | 275 | func (v *Video) decodeSequenceHeader() bool { 276 | maxHeaderSize := 64 + 2*64*8 // 64 bit header + 2x 64 byte matrix 277 | if !v.buf.has(maxHeaderSize) { 278 | return false 279 | } 280 | 281 | v.width = v.buf.read(12) 282 | v.height = v.buf.read(12) 283 | 284 | if v.width <= 0 || v.height <= 0 { 285 | return false 286 | } 287 | 288 | v.aspectRatio = videoAspectRatio[v.buf.read(4)] 289 | v.frameRate = videoPictureRate[v.buf.read(4)] 290 | v.bitRate = v.buf.read(18) 291 | 292 | // Skip marker, buffer_size and constrained bit 293 | v.buf.skip(1 + 10 + 1) 294 | 295 | // Load custom intra quant matrix? 296 | if v.buf.read1() != 0 { 297 | for i := 0; i < 64; i++ { 298 | idx := videoZigZag[i] 299 | v.intraQuantMatrix[idx] = byte(v.buf.read(8)) 300 | } 301 | } else { 302 | copy(v.intraQuantMatrix, videoIntraQuantMatrix) 303 | } 304 | 305 | // Load custom non intra quant matrix? 306 | if v.buf.read1() != 0 { 307 | for i := 0; i < 64; i++ { 308 | idx := videoZigZag[i] 309 | v.nonIntraQuantMatrix[idx] = byte(v.buf.read(8)) 310 | } 311 | } else { 312 | copy(v.nonIntraQuantMatrix, videoNonIntraQuantMatrix) 313 | } 314 | 315 | v.mbWidth = (v.width + 15) >> 4 316 | v.mbHeight = (v.height + 15) >> 4 317 | v.mbSize = v.mbWidth * v.mbHeight 318 | 319 | v.lumaWidth = v.mbWidth << 4 320 | v.lumaHeight = v.mbHeight << 4 321 | 322 | v.chromaWidth = v.mbWidth << 3 323 | v.chromaHeight = v.mbHeight << 3 324 | 325 | v.initFrame(&v.frameCurrent) 326 | v.initFrame(&v.frameForward) 327 | v.initFrame(&v.frameBackward) 328 | 329 | v.hasSequenceHeader = true 330 | 331 | return true 332 | } 333 | 334 | func (v *Video) initFrame(frame *Frame) { 335 | lumaSize := v.lumaWidth * v.lumaHeight 336 | chromaSize := v.chromaWidth * v.chromaHeight 337 | frameSize := lumaSize + 2*chromaSize 338 | 339 | base := make([]byte, frameSize) 340 | 341 | frame.Width = v.width 342 | frame.Height = v.height 343 | 344 | frame.Y.Width = v.lumaWidth 345 | frame.Y.Height = v.lumaHeight 346 | frame.Y.Data = base[0:lumaSize:lumaSize] 347 | 348 | frame.Cb.Width = v.chromaWidth 349 | frame.Cb.Height = v.chromaHeight 350 | frame.Cb.Data = base[lumaSize : lumaSize+chromaSize : lumaSize+chromaSize] 351 | 352 | frame.Cr.Width = v.chromaWidth 353 | frame.Cr.Height = v.chromaHeight 354 | frame.Cr.Data = base[lumaSize+chromaSize : frameSize : frameSize] 355 | 356 | frame.imYCbCr = image.YCbCr{ 357 | Y: frame.Y.Data, 358 | Cb: frame.Cb.Data, 359 | Cr: frame.Cr.Data, 360 | SubsampleRatio: image.YCbCrSubsampleRatio420, 361 | YStride: v.lumaWidth, 362 | CStride: v.chromaWidth, 363 | Rect: image.Rect(0, 0, v.width, v.height), 364 | } 365 | 366 | frame.imRGBA = image.RGBA{ 367 | Pix: make([]byte, v.width*v.height*4), 368 | Stride: 4 * v.width, 369 | Rect: image.Rect(0, 0, v.width, v.height), 370 | } 371 | } 372 | 373 | func (v *Video) decodePicture() { 374 | v.buf.skip(10) // skip temporalReference 375 | v.pictureType = v.buf.read(3) 376 | v.buf.skip(16) // skip vbv_delay 377 | 378 | // D frames or unknown coding type 379 | if v.pictureType <= 0 || v.pictureType > pictureTypeB { 380 | return 381 | } 382 | 383 | // Forward fullPx, fCode 384 | if v.pictureType == pictureTypePredictive || v.pictureType == pictureTypeB { 385 | v.motionForward.FullPx = v.buf.read1() 386 | fCode := v.buf.read(3) 387 | if fCode == 0 { 388 | // Ignore picture with zero fCode 389 | return 390 | } 391 | v.motionForward.RSize = fCode - 1 392 | } 393 | 394 | // Backward fullPx, fCode 395 | if v.pictureType == pictureTypeB { 396 | v.motionBackward.FullPx = v.buf.read1() 397 | fCode := v.buf.read(3) 398 | if fCode == 0 { 399 | // Ignore picture with zero fCode 400 | return 401 | } 402 | v.motionBackward.RSize = fCode - 1 403 | } 404 | 405 | frameTemp := v.frameForward 406 | if v.pictureType == pictureTypeIntra || v.pictureType == pictureTypePredictive { 407 | v.frameForward = v.frameBackward 408 | } 409 | 410 | // Find first slice start code; skip extension and user data 411 | for { 412 | v.startCode = v.buf.nextStartCode() 413 | 414 | if v.startCode != startExtension && v.startCode != startUserData { 415 | break 416 | } 417 | } 418 | 419 | // Decode all slices 420 | for startIsSlice(v.startCode) { 421 | v.decodeSlice(v.startCode & 0x000000FF) 422 | if v.macroblockAddress >= v.mbSize-2 { 423 | break 424 | } 425 | v.startCode = v.buf.nextStartCode() 426 | } 427 | 428 | // If this is a reference picture rotate the prediction pointers 429 | if v.pictureType == pictureTypeIntra || v.pictureType == pictureTypePredictive { 430 | v.frameBackward = v.frameCurrent 431 | v.frameCurrent = frameTemp 432 | } 433 | } 434 | 435 | func (v *Video) decodeSlice(slice int) { 436 | v.sliceBegin = true 437 | v.macroblockAddress = (slice-1)*v.mbWidth - 1 438 | 439 | // Reset motion vectors and DC predictors 440 | v.motionBackward.H, v.motionForward.H = 0, 0 441 | v.motionBackward.V, v.motionForward.V = 0, 0 442 | v.dcPredictor[0] = 128 443 | v.dcPredictor[1] = 128 444 | v.dcPredictor[2] = 128 445 | 446 | v.quantizerScale = v.buf.read(5) 447 | 448 | // Skip extra 449 | for v.buf.read1() != 0 { 450 | v.buf.skip(8) 451 | } 452 | 453 | for { 454 | v.decodeMacroblock() 455 | if v.macroblockAddress >= v.mbSize-1 || !v.buf.peekNonZero(23) { 456 | break 457 | } 458 | } 459 | } 460 | 461 | func (v *Video) decodeMacroblock() { 462 | // Decode increment 463 | increment := 0 464 | t := v.buf.readVlc(videoMacroblockAddressIncrement) 465 | 466 | for t == 34 { 467 | // macroblock_stuffing 468 | t = v.buf.readVlc(videoMacroblockAddressIncrement) 469 | } 470 | for t == 35 { 471 | // macroblock_escape 472 | increment += 33 473 | t = v.buf.readVlc(videoMacroblockAddressIncrement) 474 | } 475 | increment += t 476 | 477 | // Process any skipped macroblocks 478 | if v.sliceBegin { 479 | // The first increment of each slice is relative to beginning of the 480 | // previous row, not the previous macroblock 481 | v.sliceBegin = false 482 | v.macroblockAddress += increment 483 | } else { 484 | if v.macroblockAddress+increment >= v.mbSize { 485 | return // invalid 486 | } 487 | 488 | if increment > 1 { 489 | // Skipped macroblocks reset DC predictors 490 | v.dcPredictor[0] = 128 491 | v.dcPredictor[1] = 128 492 | v.dcPredictor[2] = 128 493 | 494 | // Skipped macroblocks in P-pictures reset motion vectors 495 | if v.pictureType == pictureTypePredictive { 496 | v.motionForward.H = 0 497 | v.motionForward.V = 0 498 | } 499 | } 500 | 501 | // Predict skipped macroblocks 502 | for increment > 1 { 503 | v.macroblockAddress++ 504 | v.mbRow = v.macroblockAddress / v.mbWidth 505 | v.mbCol = v.macroblockAddress % v.mbWidth 506 | 507 | v.predictMacroblock() 508 | increment-- 509 | } 510 | v.macroblockAddress++ 511 | } 512 | 513 | v.mbRow = v.macroblockAddress / v.mbWidth 514 | v.mbCol = v.macroblockAddress % v.mbWidth 515 | 516 | if v.mbCol >= v.mbWidth || v.mbRow >= v.mbHeight { 517 | return // corrupt stream 518 | } 519 | 520 | // Process the current macroblock 521 | v.macroblockType = v.buf.readVlc(videoMacroBlockType[v.pictureType]) 522 | 523 | v.macroblockIntra = v.macroblockType&0x01 != 0 524 | v.motionForward.IsSet = v.macroblockType&0x08 != 0 525 | v.motionBackward.IsSet = v.macroblockType&0x04 != 0 526 | 527 | // Quantizer scale 528 | if (v.macroblockType & 0x10) != 0 { 529 | v.quantizerScale = v.buf.read(5) 530 | } 531 | 532 | if v.macroblockIntra { 533 | // Intra-coded macroblocks reset motion vectors 534 | v.motionBackward.H, v.motionForward.H = 0, 0 535 | v.motionBackward.V, v.motionForward.V = 0, 0 536 | } else { 537 | // Non-intra macroblocks reset DC predictors 538 | v.dcPredictor[0] = 128 539 | v.dcPredictor[1] = 128 540 | v.dcPredictor[2] = 128 541 | 542 | v.decodeMotionVectors() 543 | v.predictMacroblock() 544 | } 545 | 546 | // Decode blocks 547 | cbp := 0 548 | if (v.macroblockType & 0x02) != 0 { 549 | cbp = v.buf.readVlc(videoCodeBlockPattern) 550 | } else if v.macroblockIntra { 551 | cbp = 0x3f 552 | } 553 | 554 | mask := 0x20 555 | for block := 0; block < 6; block++ { 556 | if (cbp & mask) != 0 { 557 | v.decodeBlock(block) 558 | } 559 | mask >>= 1 560 | } 561 | } 562 | 563 | func (v *Video) decodeMotionVectors() { 564 | // Forward 565 | if v.motionForward.IsSet { 566 | rSize := v.motionForward.RSize 567 | v.motionForward.H = v.decodeMotionVector(rSize, v.motionForward.H) 568 | v.motionForward.V = v.decodeMotionVector(rSize, v.motionForward.V) 569 | } else if v.pictureType == pictureTypePredictive { 570 | // No motion information in P-picture, reset vectors 571 | v.motionForward.H = 0 572 | v.motionForward.V = 0 573 | } 574 | 575 | if v.motionBackward.IsSet { 576 | rSize := v.motionBackward.RSize 577 | v.motionBackward.H = v.decodeMotionVector(rSize, v.motionBackward.H) 578 | v.motionBackward.V = v.decodeMotionVector(rSize, v.motionBackward.V) 579 | } 580 | } 581 | 582 | func (v *Video) decodeMotionVector(rSize, motion int) int { 583 | fscale := 1 << rSize 584 | mCode := v.buf.readVlc(videoMotion) 585 | var r, d int 586 | 587 | if mCode != 0 && fscale != 1 { 588 | r = v.buf.read(rSize) 589 | d = ((abs(mCode) - 1) << rSize) + r + 1 590 | if mCode < 0 { 591 | d = -d 592 | } 593 | } else { 594 | d = mCode 595 | } 596 | 597 | motion += d 598 | if motion > (fscale<<4)-1 { 599 | motion -= fscale << 5 600 | } else if motion < ((-fscale) << 4) { 601 | motion += fscale << 5 602 | } 603 | 604 | return motion 605 | } 606 | 607 | func (v *Video) predictMacroblock() { 608 | fwH := v.motionForward.H 609 | fwV := v.motionForward.V 610 | 611 | if v.motionForward.FullPx != 0 { 612 | fwH <<= 1 613 | fwV <<= 1 614 | } 615 | 616 | if v.pictureType == pictureTypeB { 617 | bwH := v.motionBackward.H 618 | bwV := v.motionBackward.V 619 | 620 | if v.motionBackward.FullPx != 0 { 621 | bwH <<= 1 622 | bwV <<= 1 623 | } 624 | 625 | if v.motionForward.IsSet { 626 | v.copyMacroblock(fwH, fwV, &v.frameForward) 627 | if v.motionBackward.IsSet { 628 | v.copyMacroblock(bwH, bwV, &v.frameBackward) 629 | } 630 | } else { 631 | v.copyMacroblock(bwH, bwV, &v.frameBackward) 632 | } 633 | } else { 634 | v.copyMacroblock(fwH, fwV, &v.frameForward) 635 | } 636 | } 637 | 638 | func (v *Video) copyMacroblock(motionH, motionV int, s *Frame) { 639 | // We use 32bit writes here 640 | d := &v.frameCurrent 641 | dY := unsafe.Slice((*uint32)(unsafe.Pointer(&d.Y.Data[0])), len(d.Y.Data)/4) 642 | dCb := unsafe.Slice((*uint32)(unsafe.Pointer(&d.Cb.Data[0])), len(d.Cb.Data)/4) 643 | dCr := unsafe.Slice((*uint32)(unsafe.Pointer(&d.Cr.Data[0])), len(d.Cr.Data)/4) 644 | 645 | // Luminance 646 | width := v.lumaWidth 647 | scan := width - 16 648 | 649 | hp := motionH >> 1 650 | vp := motionV >> 1 651 | oddH := (motionH & 1) == 1 652 | oddV := (motionV & 1) == 1 653 | 654 | si := ((v.mbRow<<4)+vp)*width + (v.mbCol << 4) + hp 655 | di := (v.mbRow*width + v.mbCol) << 2 656 | last := di + (width << 2) 657 | 658 | var y1, y2, y uint64 659 | 660 | if oddH { 661 | if oddV { 662 | for di < last { 663 | y1 = uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) 664 | si++ 665 | 666 | for x := 0; x < 4; x++ { 667 | y2 = uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) 668 | si++ 669 | y = ((y1 + y2 + 2) >> 2) & 0xff 670 | 671 | y1 = uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) 672 | si++ 673 | y |= ((y1 + y2 + 2) << 6) & 0xff00 674 | 675 | y2 = uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) 676 | si++ 677 | y |= ((y1 + y2 + 2) << 14) & 0xff0000 678 | 679 | y1 = uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) 680 | si++ 681 | y |= ((y1 + y2 + 2) << 22) & 0xff000000 682 | 683 | dY[di] = uint32(y) 684 | di++ 685 | } 686 | di += scan >> 2 687 | si += scan - 1 688 | } 689 | } else { 690 | for di < last { 691 | y1 = uint64(s.Y.Data[si]) 692 | si++ 693 | for x := 0; x < 4; x++ { 694 | y2 = uint64(s.Y.Data[si]) 695 | si++ 696 | y = ((y1 + y2 + 1) >> 1) & 0xff 697 | 698 | y1 = uint64(s.Y.Data[si]) 699 | si++ 700 | y |= ((y1 + y2 + 1) << 7) & 0xff00 701 | 702 | y2 = uint64(s.Y.Data[si]) 703 | si++ 704 | y |= ((y1 + y2 + 1) << 15) & 0xff0000 705 | 706 | y1 = uint64(s.Y.Data[si]) 707 | si++ 708 | y |= ((y1 + y2 + 1) << 23) & 0xff000000 709 | 710 | dY[di] = uint32(y) 711 | di++ 712 | } 713 | di += scan >> 2 714 | si += scan - 1 715 | } 716 | } 717 | } else { 718 | if oddV { 719 | for di < last { 720 | for x := 0; x < 4; x++ { 721 | y = ((uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) + 1) >> 1) & 0xff 722 | si++ 723 | y |= ((uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) + 1) << 7) & 0xff00 724 | si++ 725 | y |= ((uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) + 1) << 15) & 0xff0000 726 | si++ 727 | y |= ((uint64(s.Y.Data[si]) + uint64(s.Y.Data[si+width]) + 1) << 23) & 0xff000000 728 | si++ 729 | 730 | dY[di] = uint32(y) 731 | di++ 732 | } 733 | di += scan >> 2 734 | si += scan 735 | } 736 | } else { 737 | for di < last { 738 | for x := 0; x < 4; x++ { 739 | y = uint64(s.Y.Data[si]) 740 | si++ 741 | y |= uint64(s.Y.Data[si]) << 8 742 | si++ 743 | y |= uint64(s.Y.Data[si]) << 16 744 | si++ 745 | y |= uint64(s.Y.Data[si]) << 24 746 | si++ 747 | 748 | dY[di] = uint32(y) 749 | di++ 750 | } 751 | di += scan >> 2 752 | si += scan 753 | } 754 | } 755 | } 756 | 757 | // Chrominance 758 | width = v.chromaWidth 759 | scan = width - 8 760 | 761 | hp = (motionH / 2) >> 1 762 | vp = (motionV / 2) >> 1 763 | oddH = ((motionH / 2) & 1) == 1 764 | oddV = ((motionV / 2) & 1) == 1 765 | 766 | si = ((v.mbRow<<3)+vp)*width + (v.mbCol << 3) + hp 767 | di = (v.mbRow*width + v.mbCol) << 1 768 | last = di + (width << 1) 769 | 770 | var cb1, cb2, cb, cr1, cr2, cr uint64 771 | if oddH { 772 | if oddV { 773 | for di < last { 774 | cr1 = uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) 775 | cb1 = uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) 776 | si++ 777 | for x := 0; x < 2; x++ { 778 | cr2 = uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) 779 | cb2 = uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) 780 | si++ 781 | cr = ((cr1 + cr2 + 2) >> 2) & 0xff 782 | cb = ((cb1 + cb2 + 2) >> 2) & 0xff 783 | 784 | cr1 = uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) 785 | cb1 = uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) 786 | si++ 787 | cr |= ((cr1 + cr2 + 2) << 6) & 0xff00 788 | cb |= ((cb1 + cb2 + 2) << 6) & 0xff00 789 | 790 | cr2 = uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) 791 | cb2 = uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) 792 | si++ 793 | cr |= ((cr1 + cr2 + 2) << 14) & 0xff0000 794 | cb |= ((cb1 + cb2 + 2) << 14) & 0xff0000 795 | 796 | cr1 = uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) 797 | cb1 = uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) 798 | si++ 799 | cr |= ((cr1 + cr2 + 2) << 22) & 0xff000000 800 | cb |= ((cb1 + cb2 + 2) << 22) & 0xff000000 801 | 802 | dCr[di] = uint32(cr) 803 | dCb[di] = uint32(cb) 804 | di++ 805 | } 806 | di += scan >> 2 807 | si += scan - 1 808 | } 809 | } else { 810 | for di < last { 811 | cr1 = uint64(s.Cr.Data[si]) 812 | cb1 = uint64(s.Cb.Data[si]) 813 | si++ 814 | for x := 0; x < 2; x++ { 815 | cr2 = uint64(s.Cr.Data[si]) 816 | cb2 = uint64(s.Cb.Data[si]) 817 | si++ 818 | cr = ((cr1 + cr2 + 1) >> 1) & 0xff 819 | cb = ((cb1 + cb2 + 1) >> 1) & 0xff 820 | 821 | cr1 = uint64(s.Cr.Data[si]) 822 | cb1 = uint64(s.Cb.Data[si]) 823 | si++ 824 | cr |= ((cr1 + cr2 + 1) << 7) & 0xff00 825 | cb |= ((cb1 + cb2 + 1) << 7) & 0xff00 826 | 827 | cr2 = uint64(s.Cr.Data[si]) 828 | cb2 = uint64(s.Cb.Data[si]) 829 | si++ 830 | cr |= ((cr1 + cr2 + 1) << 15) & 0xff0000 831 | cb |= ((cb1 + cb2 + 1) << 15) & 0xff0000 832 | 833 | cr1 = uint64(s.Cr.Data[si]) 834 | cb1 = uint64(s.Cb.Data[si]) 835 | si++ 836 | cr |= ((cr1 + cr2 + 1) << 23) & 0xff000000 837 | cb |= ((cb1 + cb2 + 1) << 23) & 0xff000000 838 | 839 | dCr[di] = uint32(cr) 840 | dCb[di] = uint32(cb) 841 | di++ 842 | } 843 | di += scan >> 2 844 | si += scan - 1 845 | } 846 | } 847 | } else { 848 | if oddV { 849 | for di < last { 850 | for x := 0; x < 2; x++ { 851 | cr = ((uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) + 1) >> 1) & 0xff 852 | cb = ((uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) + 1) >> 1) & 0xff 853 | si++ 854 | 855 | cr |= ((uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) + 1) << 7) & 0xff00 856 | cb |= ((uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) + 1) << 7) & 0xff00 857 | si++ 858 | 859 | cr |= ((uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) + 1) << 15) & 0xff0000 860 | cb |= ((uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) + 1) << 15) & 0xff0000 861 | si++ 862 | 863 | cr |= ((uint64(s.Cr.Data[si]) + uint64(s.Cr.Data[si+width]) + 1) << 23) & 0xff000000 864 | cb |= ((uint64(s.Cb.Data[si]) + uint64(s.Cb.Data[si+width]) + 1) << 23) & 0xff000000 865 | si++ 866 | 867 | dCr[di] = uint32(cr) 868 | dCb[di] = uint32(cb) 869 | di++ 870 | } 871 | di += scan >> 2 872 | si += scan 873 | } 874 | } else { 875 | for di < last { 876 | for x := 0; x < 2; x++ { 877 | cr = uint64(s.Cr.Data[si]) 878 | cb = uint64(s.Cb.Data[si]) 879 | si++ 880 | 881 | cr |= uint64(s.Cr.Data[si]) << 8 882 | cb |= uint64(s.Cb.Data[si]) << 8 883 | si++ 884 | 885 | cr |= uint64(s.Cr.Data[si]) << 16 886 | cb |= uint64(s.Cb.Data[si]) << 16 887 | si++ 888 | 889 | cr |= uint64(s.Cr.Data[si]) << 24 890 | cb |= uint64(s.Cb.Data[si]) << 24 891 | si++ 892 | 893 | dCr[di] = uint32(cr) 894 | dCb[di] = uint32(cb) 895 | di++ 896 | } 897 | di += scan >> 2 898 | si += scan 899 | } 900 | } 901 | } 902 | } 903 | 904 | func (v *Video) decodeBlock(block int) { 905 | var n int 906 | var quantMatrix []byte 907 | 908 | // Decode DC coefficient of intra-coded blocks 909 | if v.macroblockIntra { 910 | var predictor int 911 | var dctSize int 912 | 913 | // DC prediction 914 | planeIndex := 0 915 | if block > 3 { 916 | planeIndex = block - 3 917 | } 918 | predictor = v.dcPredictor[planeIndex] 919 | dctSize = v.buf.readVlc(videoDctSize[planeIndex]) 920 | 921 | // Read DC coeff 922 | if dctSize > 0 { 923 | differential := v.buf.read(dctSize) 924 | if (differential & (1 << (dctSize - 1))) != 0 { 925 | v.blockData[0] = predictor + differential 926 | } else { 927 | v.blockData[0] = predictor + ((-1 << dctSize) | (differential + 1)) 928 | } 929 | } else { 930 | v.blockData[0] = predictor 931 | } 932 | 933 | // Save predictor value 934 | v.dcPredictor[planeIndex] = v.blockData[0] 935 | 936 | // Dequantize + premultiply 937 | v.blockData[0] <<= 3 + 5 938 | 939 | quantMatrix = v.intraQuantMatrix 940 | n = 1 941 | } else { 942 | quantMatrix = v.nonIntraQuantMatrix 943 | } 944 | 945 | // Decode AC coefficients (+DC for non-intra) 946 | level := 0 947 | for { 948 | run := 0 949 | coeff := int(v.buf.readVlcUint(videoDctCoeff)) 950 | 951 | if (coeff == 0x0001) && (n > 0) && (v.buf.read1() == 0) { 952 | // end_of_block 953 | break 954 | } 955 | 956 | if coeff == 0xffff { 957 | // escape 958 | run = v.buf.read(6) 959 | level = v.buf.read(8) 960 | switch { 961 | case level == 0: 962 | level = v.buf.read(8) 963 | case level == 128: 964 | level = v.buf.read(8) - 256 965 | case level > 128: 966 | level -= 256 967 | } 968 | } else { 969 | run = coeff >> 8 970 | level = coeff & 0xff 971 | if (v.buf.read1()) != 0 { 972 | level = -level 973 | } 974 | } 975 | 976 | n += run 977 | if n < 0 || n >= 64 { 978 | return // invalid 979 | } 980 | 981 | deZigZagged := videoZigZag[n] 982 | n++ 983 | 984 | // Dequantize, oddify, clip 985 | level <<= 1 986 | if !v.macroblockIntra { 987 | if level < 0 { 988 | level += -1 989 | } else { 990 | level += 1 991 | } 992 | } 993 | 994 | level = (level * v.quantizerScale * int(quantMatrix[deZigZagged])) >> 4 995 | if (level & 1) == 0 { 996 | if level > 0 { 997 | level -= 1 998 | } else { 999 | level -= -1 1000 | } 1001 | } 1002 | if level > 2047 { 1003 | level = 2047 1004 | } else if level < -2048 { 1005 | level = -2048 1006 | } 1007 | 1008 | // Save premultiplied coefficient 1009 | v.blockData[deZigZagged] = level * int(videoPremultiplierMatrix[deZigZagged]) 1010 | } 1011 | 1012 | // Move block to its place 1013 | var d []byte 1014 | var di int 1015 | var scan int 1016 | 1017 | if block < 4 { 1018 | d = v.frameCurrent.Y.Data 1019 | di = (v.mbRow*v.lumaWidth + v.mbCol) << 4 1020 | scan = v.lumaWidth - 8 1021 | if (block & 1) != 0 { 1022 | di += 8 1023 | } 1024 | if (block & 2) != 0 { 1025 | di += v.lumaWidth << 3 1026 | } 1027 | } else { 1028 | if block == 4 { 1029 | d = v.frameCurrent.Cb.Data 1030 | } else { 1031 | d = v.frameCurrent.Cr.Data 1032 | } 1033 | di = ((v.mbRow * v.lumaWidth) << 2) + (v.mbCol << 3) 1034 | scan = (v.lumaWidth >> 1) - 8 1035 | } 1036 | 1037 | s := v.blockData 1038 | if v.macroblockIntra { 1039 | // Overwrite (no prediction) 1040 | if n == 1 { 1041 | value := (s[0] + 128) >> 8 1042 | copyValueToDest(int(clamp(value)), d, di, scan) 1043 | s[0] = 0 1044 | } else { 1045 | v.idct(s) 1046 | copyBlockToDest(s, d, di, scan) 1047 | for i := range v.blockData { 1048 | v.blockData[i] = 0 1049 | } 1050 | } 1051 | } else { 1052 | // Add data to the predicted macroblock 1053 | if n == 1 { 1054 | value := (s[0] + 128) >> 8 1055 | addValueToDest(value, d, di, scan) 1056 | s[0] = 0 1057 | } else { 1058 | v.idct(s) 1059 | addBlockToDest(s, d, di, scan) 1060 | for i := range v.blockData { 1061 | v.blockData[i] = 0 1062 | } 1063 | } 1064 | } 1065 | } 1066 | 1067 | func (v *Video) idct(block []int) { 1068 | // See http://vsr.informatik.tu-chemnitz.de/~jan/MPEG/HTML/IDCT.html for more info. 1069 | 1070 | var b1, b3, b4, b6, b7, tmp1, tmp2, m0, 1071 | x0, x1, x2, x3, x4, y3, y4, y5, y6, y7 int 1072 | 1073 | // Transform columns 1074 | for i := 0; i < 8; i++ { 1075 | b1 = block[4*8+i] 1076 | b3 = block[2*8+i] + block[6*8+i] 1077 | b4 = block[5*8+i] - block[3*8+i] 1078 | tmp1 = block[1*8+i] + block[7*8+i] 1079 | tmp2 = block[3*8+i] + block[5*8+i] 1080 | b6 = block[1*8+i] - block[7*8+i] 1081 | b7 = tmp1 + tmp2 1082 | m0 = block[0*8+i] 1083 | x4 = ((b6*473 - b4*196 + 128) >> 8) - b7 1084 | x0 = x4 - (((tmp1-tmp2)*362 + 128) >> 8) 1085 | x1 = m0 - b1 1086 | x2 = (((block[2*8+i]-block[6*8+i])*362 + 128) >> 8) - b3 1087 | x3 = m0 + b1 1088 | y3 = x1 + x2 1089 | y4 = x3 + b3 1090 | y5 = x1 - x2 1091 | y6 = x3 - b3 1092 | y7 = -x0 - ((b4*473 + b6*196 + 128) >> 8) 1093 | block[0*8+i] = b7 + y4 1094 | block[1*8+i] = x4 + y3 1095 | block[2*8+i] = y5 - x0 1096 | block[3*8+i] = y6 - y7 1097 | block[4*8+i] = y6 + y7 1098 | block[5*8+i] = x0 + y5 1099 | block[6*8+i] = y3 - x4 1100 | block[7*8+i] = y4 - b7 1101 | } 1102 | 1103 | // Transform rows 1104 | for i := 0; i < 64; i += 8 { 1105 | b1 = block[4+i] 1106 | b3 = block[2+i] + block[6+i] 1107 | b4 = block[5+i] - block[3+i] 1108 | tmp1 = block[1+i] + block[7+i] 1109 | tmp2 = block[3+i] + block[5+i] 1110 | b6 = block[1+i] - block[7+i] 1111 | b7 = tmp1 + tmp2 1112 | m0 = block[0+i] 1113 | x4 = ((b6*473 - b4*196 + 128) >> 8) - b7 1114 | x0 = x4 - (((tmp1-tmp2)*362 + 128) >> 8) 1115 | x1 = m0 - b1 1116 | x2 = (((block[2+i]-block[6+i])*362 + 128) >> 8) - b3 1117 | x3 = m0 + b1 1118 | y3 = x1 + x2 1119 | y4 = x3 + b3 1120 | y5 = x1 - x2 1121 | y6 = x3 - b3 1122 | y7 = -x0 - ((b4*473 + b6*196 + 128) >> 8) 1123 | block[0+i] = (b7 + y4 + 128) >> 8 1124 | block[1+i] = (x4 + y3 + 128) >> 8 1125 | block[2+i] = (y5 - x0 + 128) >> 8 1126 | block[3+i] = (y6 - y7 + 128) >> 8 1127 | block[4+i] = (y6 + y7 + 128) >> 8 1128 | block[5+i] = (x0 + y5 + 128) >> 8 1129 | block[6+i] = (y3 - x4 + 128) >> 8 1130 | block[7+i] = (y4 - b7 + 128) >> 8 1131 | } 1132 | } 1133 | 1134 | const ( 1135 | pictureTypeIntra = 1 1136 | pictureTypePredictive = 2 1137 | pictureTypeB = 3 1138 | 1139 | startPicture = 0x00 1140 | startSliceFirst = 0x01 1141 | startSliceLast = 0xAF 1142 | startUserData = 0xB2 1143 | startSequence = 0xB3 1144 | startExtension = 0xB5 1145 | ) 1146 | 1147 | func copyBlockToDest(block []int, dest []byte, index, scan int) { 1148 | for n := 0; n < 64; n += 8 { 1149 | dest[index+0] = clamp(block[n+0]) 1150 | dest[index+1] = clamp(block[n+1]) 1151 | dest[index+2] = clamp(block[n+2]) 1152 | dest[index+3] = clamp(block[n+3]) 1153 | dest[index+4] = clamp(block[n+4]) 1154 | dest[index+5] = clamp(block[n+5]) 1155 | dest[index+6] = clamp(block[n+6]) 1156 | dest[index+7] = clamp(block[n+7]) 1157 | 1158 | index += scan + 8 1159 | } 1160 | } 1161 | 1162 | func addBlockToDest(block []int, dest []byte, index, scan int) { 1163 | for n := 0; n < 64; n += 8 { 1164 | dest[index+0] = clamp(int(dest[index+0]) + block[n+0]) 1165 | dest[index+1] = clamp(int(dest[index+1]) + block[n+1]) 1166 | dest[index+2] = clamp(int(dest[index+2]) + block[n+2]) 1167 | dest[index+3] = clamp(int(dest[index+3]) + block[n+3]) 1168 | dest[index+4] = clamp(int(dest[index+4]) + block[n+4]) 1169 | dest[index+5] = clamp(int(dest[index+5]) + block[n+5]) 1170 | dest[index+6] = clamp(int(dest[index+6]) + block[n+6]) 1171 | dest[index+7] = clamp(int(dest[index+7]) + block[n+7]) 1172 | 1173 | index += scan + 8 1174 | } 1175 | } 1176 | 1177 | func copyValueToDest(value int, dest []byte, index, scan int) { 1178 | val := clamp(value) 1179 | for n := 0; n < 64; n += 8 { 1180 | dest[index+0] = val 1181 | dest[index+1] = val 1182 | dest[index+2] = val 1183 | dest[index+3] = val 1184 | dest[index+4] = val 1185 | dest[index+5] = val 1186 | dest[index+6] = val 1187 | dest[index+7] = val 1188 | 1189 | index += scan + 8 1190 | } 1191 | } 1192 | 1193 | func addValueToDest(value int, dest []byte, index, scan int) { 1194 | for n := 0; n < 64; n += 8 { 1195 | dest[index+0] = clamp(int(dest[index+0]) + value) 1196 | dest[index+1] = clamp(int(dest[index+1]) + value) 1197 | dest[index+2] = clamp(int(dest[index+2]) + value) 1198 | dest[index+3] = clamp(int(dest[index+3]) + value) 1199 | dest[index+4] = clamp(int(dest[index+4]) + value) 1200 | dest[index+5] = clamp(int(dest[index+5]) + value) 1201 | dest[index+6] = clamp(int(dest[index+6]) + value) 1202 | dest[index+7] = clamp(int(dest[index+7]) + value) 1203 | 1204 | index += scan + 8 1205 | } 1206 | } 1207 | 1208 | func abs(x int) int { 1209 | if x < 0 { 1210 | return -x 1211 | } 1212 | 1213 | return x 1214 | } 1215 | 1216 | func clamp(n int) byte { 1217 | if n > 255 { 1218 | n = 255 1219 | } else if n < 0 { 1220 | n = 0 1221 | } 1222 | 1223 | return byte(n) 1224 | } 1225 | 1226 | func startIsSlice(c int) bool { 1227 | if c >= startSliceFirst && c <= startSliceLast { 1228 | return true 1229 | } 1230 | 1231 | return false 1232 | } 1233 | 1234 | type motion struct { 1235 | FullPx int 1236 | RSize int 1237 | H int 1238 | V int 1239 | IsSet bool 1240 | } 1241 | 1242 | var videoPictureRate = []float64{ 1243 | 0.000, 23.976, 24.000, 25.000, 29.970, 30.000, 50.000, 59.940, 1244 | 60.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 1245 | } 1246 | 1247 | var videoAspectRatio = []float64{ 1248 | 0.0000, 1.0000, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 1249 | 0.9375, 0.9815, 1.0255, 1.0695, 1.1250, 1.1575, 1.2015, 0.0000, 1250 | } 1251 | 1252 | var videoZigZag = []byte{ 1253 | 0, 1, 8, 16, 9, 2, 3, 10, 1254 | 17, 24, 32, 25, 18, 11, 4, 5, 1255 | 12, 19, 26, 33, 40, 48, 41, 34, 1256 | 27, 20, 13, 6, 7, 14, 21, 28, 1257 | 35, 42, 49, 56, 57, 50, 43, 36, 1258 | 29, 22, 15, 23, 30, 37, 44, 51, 1259 | 58, 59, 52, 45, 38, 31, 39, 46, 1260 | 53, 60, 61, 54, 47, 55, 62, 63, 1261 | } 1262 | 1263 | var videoIntraQuantMatrix = []byte{ 1264 | 8, 16, 19, 22, 26, 27, 29, 34, 1265 | 16, 16, 22, 24, 27, 29, 34, 37, 1266 | 19, 22, 26, 27, 29, 34, 34, 38, 1267 | 22, 22, 26, 27, 29, 34, 37, 40, 1268 | 22, 26, 27, 29, 32, 35, 40, 48, 1269 | 26, 27, 29, 32, 35, 40, 48, 58, 1270 | 26, 27, 29, 34, 38, 46, 56, 69, 1271 | 27, 29, 35, 38, 46, 56, 69, 83, 1272 | } 1273 | 1274 | var videoNonIntraQuantMatrix = []byte{ 1275 | 16, 16, 16, 16, 16, 16, 16, 16, 1276 | 16, 16, 16, 16, 16, 16, 16, 16, 1277 | 16, 16, 16, 16, 16, 16, 16, 16, 1278 | 16, 16, 16, 16, 16, 16, 16, 16, 1279 | 16, 16, 16, 16, 16, 16, 16, 16, 1280 | 16, 16, 16, 16, 16, 16, 16, 16, 1281 | 16, 16, 16, 16, 16, 16, 16, 16, 1282 | 16, 16, 16, 16, 16, 16, 16, 16, 1283 | } 1284 | 1285 | var videoPremultiplierMatrix = []byte{ 1286 | 32, 44, 42, 38, 32, 25, 17, 9, 1287 | 44, 62, 58, 52, 44, 35, 24, 12, 1288 | 42, 58, 55, 49, 42, 33, 23, 12, 1289 | 38, 52, 49, 44, 38, 30, 20, 10, 1290 | 32, 44, 42, 38, 32, 25, 17, 9, 1291 | 25, 35, 33, 30, 25, 20, 14, 7, 1292 | 17, 24, 23, 20, 17, 14, 9, 5, 1293 | 9, 12, 12, 10, 9, 7, 5, 2, 1294 | } 1295 | 1296 | var videoMacroblockAddressIncrement = []vlc{ 1297 | {1 << 1, 0}, {0, 1}, // 0: x 1298 | {2 << 1, 0}, {3 << 1, 0}, // 1: 0x 1299 | {4 << 1, 0}, {5 << 1, 0}, // 2: 00x 1300 | {0, 3}, {0, 2}, // 3: 01x 1301 | {6 << 1, 0}, {7 << 1, 0}, // 4: 000x 1302 | {0, 5}, {0, 4}, // 5: 001x 1303 | {8 << 1, 0}, {9 << 1, 0}, // 6: 0000x 1304 | {0, 7}, {0, 6}, // 7: 0001x 1305 | {10 << 1, 0}, {11 << 1, 0}, // 8: 0000 0x 1306 | {12 << 1, 0}, {13 << 1, 0}, // 9: 0000 1x 1307 | {14 << 1, 0}, {15 << 1, 0}, // 10: 0000 00x 1308 | {16 << 1, 0}, {17 << 1, 0}, // 11: 0000 01x 1309 | {18 << 1, 0}, {19 << 1, 0}, // 12: 0000 10x 1310 | {0, 9}, {0, 8}, // 13: 0000 11x 1311 | {-1, 0}, {20 << 1, 0}, // 14: 0000 000x 1312 | {-1, 0}, {21 << 1, 0}, // 15: 0000 001x 1313 | {22 << 1, 0}, {23 << 1, 0}, // 16: 0000 010x 1314 | {0, 15}, {0, 14}, // 17: 0000 011x 1315 | {0, 13}, {0, 12}, // 18: 0000 100x 1316 | {0, 11}, {0, 10}, // 19: 0000 101x 1317 | {24 << 1, 0}, {25 << 1, 0}, // 20: 0000 0001x 1318 | {26 << 1, 0}, {27 << 1, 0}, // 21: 0000 0011x 1319 | {28 << 1, 0}, {29 << 1, 0}, // 22: 0000 0100x 1320 | {30 << 1, 0}, {31 << 1, 0}, // 23: 0000 0101x 1321 | {32 << 1, 0}, {-1, 0}, // 24: 0000 0001 0x 1322 | {-1, 0}, {33 << 1, 0}, // 25: 0000 0001 1x 1323 | {34 << 1, 0}, {35 << 1, 0}, // 26: 0000 0011 0x 1324 | {36 << 1, 0}, {37 << 1, 0}, // 27: 0000 0011 1x 1325 | {38 << 1, 0}, {39 << 1, 0}, // 28: 0000 0100 0x 1326 | {0, 21}, {0, 20}, // 29: 0000 0100 1x 1327 | {0, 19}, {0, 18}, // 30: 0000 0101 0x 1328 | {0, 17}, {0, 16}, // 31: 0000 0101 1x 1329 | {0, 35}, {-1, 0}, // 32: 0000 0001 00x 1330 | {-1, 0}, {0, 34}, // 33: 0000 0001 11x 1331 | {0, 33}, {0, 32}, // 34: 0000 0011 00x 1332 | {0, 31}, {0, 30}, // 35: 0000 0011 01x 1333 | {0, 29}, {0, 28}, // 36: 0000 0011 10x 1334 | {0, 27}, {0, 26}, // 37: 0000 0011 11x 1335 | {0, 25}, {0, 24}, // 38: 0000 0100 00x 1336 | {0, 23}, {0, 22}, // 39: 0000 0100 01x 1337 | } 1338 | 1339 | var videoMacroblockTypeIntra = []vlc{ 1340 | {1 << 1, 0}, {0, 0x01}, // 0: x 1341 | {-1, 0}, {0, 0x11}, // 1: 0x 1342 | } 1343 | 1344 | var videoMacroblockTypePredictive = []vlc{ 1345 | {1 << 1, 0}, {0, 0x0a}, // 0: x 1346 | {2 << 1, 0}, {0, 0x02}, // 1: 0x 1347 | {3 << 1, 0}, {0, 0x08}, // 2: 00x 1348 | {4 << 1, 0}, {5 << 1, 0}, // 3: 000x 1349 | {6 << 1, 0}, {0, 0x12}, // 4: 0000x 1350 | {0, 0x1a}, {0, 0x01}, // 5: 0001x 1351 | {-1, 0}, {0, 0x11}, // 6: 0000 0x 1352 | } 1353 | 1354 | var videoMacroblockTypeB = []vlc{ 1355 | {1 << 1, 0}, {2 << 1, 0}, // 0: x 1356 | {3 << 1, 0}, {4 << 1, 0}, // 1: 0x 1357 | {0, 0x0c}, {0, 0x0e}, // 2: 1x 1358 | {5 << 1, 0}, {6 << 1, 0}, // 3: 00x 1359 | {0, 0x04}, {0, 0x06}, // 4: 01x 1360 | {7 << 1, 0}, {8 << 1, 0}, // 5: 000x 1361 | {0, 0x08}, {0, 0x0a}, // 6: 001x 1362 | {9 << 1, 0}, {10 << 1, 0}, // 7: 0000x 1363 | {0, 0x1e}, {0, 0x01}, // 8: 0001x 1364 | {-1, 0}, {0, 0x11}, // 9: 0000 0x 1365 | {0, 0x16}, {0, 0x1a}, // 10: 0000 1x 1366 | } 1367 | 1368 | var videoMacroBlockType = [][]vlc{ 1369 | nil, 1370 | videoMacroblockTypeIntra, 1371 | videoMacroblockTypePredictive, 1372 | videoMacroblockTypeB, 1373 | } 1374 | 1375 | var videoCodeBlockPattern = []vlc{ 1376 | {1 << 1, 0}, {2 << 1, 0}, // 0: x 1377 | {3 << 1, 0}, {4 << 1, 0}, // 1: 0x 1378 | {5 << 1, 0}, {6 << 1, 0}, // 2: 1x 1379 | {7 << 1, 0}, {8 << 1, 0}, // 3: 00x 1380 | {9 << 1, 0}, {10 << 1, 0}, // 4: 01x 1381 | {11 << 1, 0}, {12 << 1, 0}, // 5: 10x 1382 | {13 << 1, 0}, {0, 60}, // 6: 11x 1383 | {14 << 1, 0}, {15 << 1, 0}, // 7: 000x 1384 | {16 << 1, 0}, {17 << 1, 0}, // 8: 001x 1385 | {18 << 1, 0}, {19 << 1, 0}, // 9: 010x 1386 | {20 << 1, 0}, {21 << 1, 0}, // 10: 011x 1387 | {22 << 1, 0}, {23 << 1, 0}, // 11: 100x 1388 | {0, 32}, {0, 16}, // 12: 101x 1389 | {0, 8}, {0, 4}, // 13: 110x 1390 | {24 << 1, 0}, {25 << 1, 0}, // 14: 0000x 1391 | {26 << 1, 0}, {27 << 1, 0}, // 15: 0001x 1392 | {28 << 1, 0}, {29 << 1, 0}, // 16: 0010x 1393 | {30 << 1, 0}, {31 << 1, 0}, // 17: 0011x 1394 | {0, 62}, {0, 2}, // 18: 0100x 1395 | {0, 61}, {0, 1}, // 19: 0101x 1396 | {0, 56}, {0, 52}, // 20: 0110x 1397 | {0, 44}, {0, 28}, // 21: 0111x 1398 | {0, 40}, {0, 20}, // 22: 1000x 1399 | {0, 48}, {0, 12}, // 23: 1001x 1400 | {32 << 1, 0}, {33 << 1, 0}, // 24: 0000 0x 1401 | {34 << 1, 0}, {35 << 1, 0}, // 25: 0000 1x 1402 | {36 << 1, 0}, {37 << 1, 0}, // 26: 0001 0x 1403 | {38 << 1, 0}, {39 << 1, 0}, // 27: 0001 1x 1404 | {40 << 1, 0}, {41 << 1, 0}, // 28: 0010 0x 1405 | {42 << 1, 0}, {43 << 1, 0}, // 29: 0010 1x 1406 | {0, 63}, {0, 3}, // 30: 0011 0x 1407 | {0, 36}, {0, 24}, // 31: 0011 1x 1408 | {44 << 1, 0}, {45 << 1, 0}, // 32: 0000 00x 1409 | {46 << 1, 0}, {47 << 1, 0}, // 33: 0000 01x 1410 | {48 << 1, 0}, {49 << 1, 0}, // 34: 0000 10x 1411 | {50 << 1, 0}, {51 << 1, 0}, // 35: 0000 11x 1412 | {52 << 1, 0}, {53 << 1, 0}, // 36: 0001 00x 1413 | {54 << 1, 0}, {55 << 1, 0}, // 37: 0001 01x 1414 | {56 << 1, 0}, {57 << 1, 0}, // 38: 0001 10x 1415 | {58 << 1, 0}, {59 << 1, 0}, // 39: 0001 11x 1416 | {0, 34}, {0, 18}, // 40: 0010 00x 1417 | {0, 10}, {0, 6}, // 41: 0010 01x 1418 | {0, 33}, {0, 17}, // 42: 0010 10x 1419 | {0, 9}, {0, 5}, // 43: 0010 11x 1420 | {-1, 0}, {60 << 1, 0}, // 44: 0000 000x 1421 | {61 << 1, 0}, {62 << 1, 0}, // 45: 0000 001x 1422 | {0, 58}, {0, 54}, // 46: 0000 010x 1423 | {0, 46}, {0, 30}, // 47: 0000 011x 1424 | {0, 57}, {0, 53}, // 48: 0000 100x 1425 | {0, 45}, {0, 29}, // 49: 0000 101x 1426 | {0, 38}, {0, 26}, // 50: 0000 110x 1427 | {0, 37}, {0, 25}, // 51: 0000 111x 1428 | {0, 43}, {0, 23}, // 52: 0001 000x 1429 | {0, 51}, {0, 15}, // 53: 0001 001x 1430 | {0, 42}, {0, 22}, // 54: 0001 010x 1431 | {0, 50}, {0, 14}, // 55: 0001 011x 1432 | {0, 41}, {0, 21}, // 56: 0001 100x 1433 | {0, 49}, {0, 13}, // 57: 0001 101x 1434 | {0, 35}, {0, 19}, // 58: 0001 110x 1435 | {0, 11}, {0, 7}, // 59: 0001 111x 1436 | {0, 39}, {0, 27}, // 60: 0000 0001x 1437 | {0, 59}, {0, 55}, // 61: 0000 0010x 1438 | {0, 47}, {0, 31}, // 62: 0000 0011x 1439 | } 1440 | 1441 | var videoMotion = []vlc{ 1442 | {1 << 1, 0}, {0, 0}, // 0: x 1443 | {2 << 1, 0}, {3 << 1, 0}, // 1: 0x 1444 | {4 << 1, 0}, {5 << 1, 0}, // 2: 00x 1445 | {0, 1}, {0, -1}, // 3: 01x 1446 | {6 << 1, 0}, {7 << 1, 0}, // 4: 000x 1447 | {0, 2}, {0, -2}, // 5: 001x 1448 | {8 << 1, 0}, {9 << 1, 0}, // 6: 0000x 1449 | {0, 3}, {0, -3}, // 7: 0001x 1450 | {10 << 1, 0}, {11 << 1, 0}, // 8: 0000 0x 1451 | {12 << 1, 0}, {13 << 1, 0}, // 9: 0000 1x 1452 | {-1, 0}, {14 << 1, 0}, // 10: 0000 00x 1453 | {15 << 1, 0}, {16 << 1, 0}, // 11: 0000 01x 1454 | {17 << 1, 0}, {18 << 1, 0}, // 12: 0000 10x 1455 | {0, 4}, {0, -4}, // 13: 0000 11x 1456 | {-1, 0}, {19 << 1, 0}, // 14: 0000 001x 1457 | {20 << 1, 0}, {21 << 1, 0}, // 15: 0000 010x 1458 | {0, 7}, {0, -7}, // 16: 0000 011x 1459 | {0, 6}, {0, -6}, // 17: 0000 100x 1460 | {0, 5}, {0, -5}, // 18: 0000 101x 1461 | {22 << 1, 0}, {23 << 1, 0}, // 19: 0000 0011x 1462 | {24 << 1, 0}, {25 << 1, 0}, // 20: 0000 0100x 1463 | {26 << 1, 0}, {27 << 1, 0}, // 21: 0000 0101x 1464 | {28 << 1, 0}, {29 << 1, 0}, // 22: 0000 0011 0x 1465 | {30 << 1, 0}, {31 << 1, 0}, // 23: 0000 0011 1x 1466 | {32 << 1, 0}, {33 << 1, 0}, // 24: 0000 0100 0x 1467 | {0, 10}, {0, -10}, // 25: 0000 0100 1x 1468 | {0, 9}, {0, -9}, // 26: 0000 0101 0x 1469 | {0, 8}, {0, -8}, // 27: 0000 0101 1x 1470 | {0, 16}, {0, -16}, // 28: 0000 0011 00x 1471 | {0, 15}, {0, -15}, // 29: 0000 0011 01x 1472 | {0, 14}, {0, -14}, // 30: 0000 0011 10x 1473 | {0, 13}, {0, -13}, // 31: 0000 0011 11x 1474 | {0, 12}, {0, -12}, // 32: 0000 0100 00x 1475 | {0, 11}, {0, -11}, // 33: 0000 0100 01x 1476 | } 1477 | 1478 | var videoDctSizeLuminance = []vlc{ 1479 | {1 << 1, 0}, {2 << 1, 0}, // 0: x 1480 | {0, 1}, {0, 2}, // 1: 0x 1481 | {3 << 1, 0}, {4 << 1, 0}, // 2: 1x 1482 | {0, 0}, {0, 3}, // 3: 10x 1483 | {0, 4}, {5 << 1, 0}, // 4: 11x 1484 | {0, 5}, {6 << 1, 0}, // 5: 111x 1485 | {0, 6}, {7 << 1, 0}, // 6: 1111x 1486 | {0, 7}, {8 << 1, 0}, // 7: 1111 1x 1487 | {0, 8}, {-1, 0}, // 8: 1111 11x 1488 | } 1489 | 1490 | var videoDctSizeChrominance = []vlc{ 1491 | {1 << 1, 0}, {2 << 1, 0}, // 0: x 1492 | {0, 0}, {0, 1}, // 1: 0x 1493 | {0, 2}, {3 << 1, 0}, // 2: 1x 1494 | {0, 3}, {4 << 1, 0}, // 3: 11x 1495 | {0, 4}, {5 << 1, 0}, // 4: 111x 1496 | {0, 5}, {6 << 1, 0}, // 5: 1111x 1497 | {0, 6}, {7 << 1, 0}, // 6: 1111 1x 1498 | {0, 7}, {8 << 1, 0}, // 7: 1111 11x 1499 | {0, 8}, {-1, 0}, // 8: 1111 111x 1500 | } 1501 | 1502 | var videoDctSize = [][]vlc{ 1503 | videoDctSizeLuminance, 1504 | videoDctSizeChrominance, 1505 | videoDctSizeChrominance, 1506 | } 1507 | 1508 | // dct_coeff bitmap: 1509 | // 1510 | // 0xff00 run 1511 | // 0x00ff level 1512 | // 1513 | // Decoded values are unsigned. Sign bit follows in the stream. 1514 | var videoDctCoeff = []vlcUint{ 1515 | {1 << 1, 0}, {0, 0x0001}, // 0: x 1516 | {2 << 1, 0}, {3 << 1, 0}, // 1: 0x 1517 | {4 << 1, 0}, {5 << 1, 0}, // 2: 00x 1518 | {6 << 1, 0}, {0, 0x0101}, // 3: 01x 1519 | {7 << 1, 0}, {8 << 1, 0}, // 4: 000x 1520 | {9 << 1, 0}, {10 << 1, 0}, // 5: 001x 1521 | {0, 0x0002}, {0, 0x0201}, // 6: 010x 1522 | {11 << 1, 0}, {12 << 1, 0}, // 7: 0000x 1523 | {13 << 1, 0}, {14 << 1, 0}, // 8: 0001x 1524 | {15 << 1, 0}, {0, 0x0003}, // 9: 0010x 1525 | {0, 0x0401}, {0, 0x0301}, // 10: 0011x 1526 | {16 << 1, 0}, {0, 0xffff}, // 11: 0000 0x 1527 | {17 << 1, 0}, {18 << 1, 0}, // 12: 0000 1x 1528 | {0, 0x0701}, {0, 0x0601}, // 13: 0001 0x 1529 | {0, 0x0102}, {0, 0x0501}, // 14: 0001 1x 1530 | {19 << 1, 0}, {20 << 1, 0}, // 15: 0010 0x 1531 | {21 << 1, 0}, {22 << 1, 0}, // 16: 0000 00x 1532 | {0, 0x0202}, {0, 0x0901}, // 17: 0000 10x 1533 | {0, 0x0004}, {0, 0x0801}, // 18: 0000 11x 1534 | {23 << 1, 0}, {24 << 1, 0}, // 19: 0010 00x 1535 | {25 << 1, 0}, {26 << 1, 0}, // 20: 0010 01x 1536 | {27 << 1, 0}, {28 << 1, 0}, // 21: 0000 000x 1537 | {29 << 1, 0}, {30 << 1, 0}, // 22: 0000 001x 1538 | {0, 0x0d01}, {0, 0x0006}, // 23: 0010 000x 1539 | {0, 0x0c01}, {0, 0x0b01}, // 24: 0010 001x 1540 | {0, 0x0302}, {0, 0x0103}, // 25: 0010 010x 1541 | {0, 0x0005}, {0, 0x0a01}, // 26: 0010 011x 1542 | {31 << 1, 0}, {32 << 1, 0}, // 27: 0000 0000x 1543 | {33 << 1, 0}, {34 << 1, 0}, // 28: 0000 0001x 1544 | {35 << 1, 0}, {36 << 1, 0}, // 29: 0000 0010x 1545 | {37 << 1, 0}, {38 << 1, 0}, // 30: 0000 0011x 1546 | {39 << 1, 0}, {40 << 1, 0}, // 31: 0000 0000 0x 1547 | {41 << 1, 0}, {42 << 1, 0}, // 32: 0000 0000 1x 1548 | {43 << 1, 0}, {44 << 1, 0}, // 33: 0000 0001 0x 1549 | {45 << 1, 0}, {46 << 1, 0}, // 34: 0000 0001 1x 1550 | {0, 0x1001}, {0, 0x0502}, // 35: 0000 0010 0x 1551 | {0, 0x0007}, {0, 0x0203}, // 36: 0000 0010 1x 1552 | {0, 0x0104}, {0, 0x0f01}, // 37: 0000 0011 0x 1553 | {0, 0x0e01}, {0, 0x0402}, // 38: 0000 0011 1x 1554 | {47 << 1, 0}, {48 << 1, 0}, // 39: 0000 0000 00x 1555 | {49 << 1, 0}, {50 << 1, 0}, // 40: 0000 0000 01x 1556 | {51 << 1, 0}, {52 << 1, 0}, // 41: 0000 0000 10x 1557 | {53 << 1, 0}, {54 << 1, 0}, // 42: 0000 0000 11x 1558 | {55 << 1, 0}, {56 << 1, 0}, // 43: 0000 0001 00x 1559 | {57 << 1, 0}, {58 << 1, 0}, // 44: 0000 0001 01x 1560 | {59 << 1, 0}, {60 << 1, 0}, // 45: 0000 0001 10x 1561 | {61 << 1, 0}, {62 << 1, 0}, // 46: 0000 0001 11x 1562 | {-1, 0}, {63 << 1, 0}, // 47: 0000 0000 000x 1563 | {64 << 1, 0}, {65 << 1, 0}, // 48: 0000 0000 001x 1564 | {66 << 1, 0}, {67 << 1, 0}, // 49: 0000 0000 010x 1565 | {68 << 1, 0}, {69 << 1, 0}, // 50: 0000 0000 011x 1566 | {70 << 1, 0}, {71 << 1, 0}, // 51: 0000 0000 100x 1567 | {72 << 1, 0}, {73 << 1, 0}, // 52: 0000 0000 101x 1568 | {74 << 1, 0}, {75 << 1, 0}, // 53: 0000 0000 110x 1569 | {76 << 1, 0}, {77 << 1, 0}, // 54: 0000 0000 111x 1570 | {0, 0x000b}, {0, 0x0802}, // 55: 0000 0001 000x 1571 | {0, 0x0403}, {0, 0x000a}, // 56: 0000 0001 001x 1572 | {0, 0x0204}, {0, 0x0702}, // 57: 0000 0001 010x 1573 | {0, 0x1501}, {0, 0x1401}, // 58: 0000 0001 011x 1574 | {0, 0x0009}, {0, 0x1301}, // 59: 0000 0001 100x 1575 | {0, 0x1201}, {0, 0x0105}, // 60: 0000 0001 101x 1576 | {0, 0x0303}, {0, 0x0008}, // 61: 0000 0001 110x 1577 | {0, 0x0602}, {0, 0x1101}, // 62: 0000 0001 111x 1578 | {78 << 1, 0}, {79 << 1, 0}, // 63: 0000 0000 0001x 1579 | {80 << 1, 0}, {81 << 1, 0}, // 64: 0000 0000 0010x 1580 | {82 << 1, 0}, {83 << 1, 0}, // 65: 0000 0000 0011x 1581 | {84 << 1, 0}, {85 << 1, 0}, // 66: 0000 0000 0100x 1582 | {86 << 1, 0}, {87 << 1, 0}, // 67: 0000 0000 0101x 1583 | {88 << 1, 0}, {89 << 1, 0}, // 68: 0000 0000 0110x 1584 | {90 << 1, 0}, {91 << 1, 0}, // 69: 0000 0000 0111x 1585 | {0, 0x0a02}, {0, 0x0902}, // 70: 0000 0000 1000x 1586 | {0, 0x0503}, {0, 0x0304}, // 71: 0000 0000 1001x 1587 | {0, 0x0205}, {0, 0x0107}, // 72: 0000 0000 1010x 1588 | {0, 0x0106}, {0, 0x000f}, // 73: 0000 0000 1011x 1589 | {0, 0x000e}, {0, 0x000d}, // 74: 0000 0000 1100x 1590 | {0, 0x000c}, {0, 0x1a01}, // 75: 0000 0000 1101x 1591 | {0, 0x1901}, {0, 0x1801}, // 76: 0000 0000 1110x 1592 | {0, 0x1701}, {0, 0x1601}, // 77: 0000 0000 1111x 1593 | {92 << 1, 0}, {93 << 1, 0}, // 78: 0000 0000 0001 0x 1594 | {94 << 1, 0}, {95 << 1, 0}, // 79: 0000 0000 0001 1x 1595 | {96 << 1, 0}, {97 << 1, 0}, // 80: 0000 0000 0010 0x 1596 | {98 << 1, 0}, {99 << 1, 0}, // 81: 0000 0000 0010 1x 1597 | {100 << 1, 0}, {101 << 1, 0}, // 82: 0000 0000 0011 0x 1598 | {102 << 1, 0}, {103 << 1, 0}, // 83: 0000 0000 0011 1x 1599 | {0, 0x001f}, {0, 0x001e}, // 84: 0000 0000 0100 0x 1600 | {0, 0x001d}, {0, 0x001c}, // 85: 0000 0000 0100 1x 1601 | {0, 0x001b}, {0, 0x001a}, // 86: 0000 0000 0101 0x 1602 | {0, 0x0019}, {0, 0x0018}, // 87: 0000 0000 0101 1x 1603 | {0, 0x0017}, {0, 0x0016}, // 88: 0000 0000 0110 0x 1604 | {0, 0x0015}, {0, 0x0014}, // 89: 0000 0000 0110 1x 1605 | {0, 0x0013}, {0, 0x0012}, // 90: 0000 0000 0111 0x 1606 | {0, 0x0011}, {0, 0x0010}, // 91: 0000 0000 0111 1x 1607 | {104 << 1, 0}, {105 << 1, 0}, // 92: 0000 0000 0001 00x 1608 | {106 << 1, 0}, {107 << 1, 0}, // 93: 0000 0000 0001 01x 1609 | {108 << 1, 0}, {109 << 1, 0}, // 94: 0000 0000 0001 10x 1610 | {110 << 1, 0}, {111 << 1, 0}, // 95: 0000 0000 0001 11x 1611 | {0, 0x0028}, {0, 0x0027}, // 96: 0000 0000 0010 00x 1612 | {0, 0x0026}, {0, 0x0025}, // 97: 0000 0000 0010 01x 1613 | {0, 0x0024}, {0, 0x0023}, // 98: 0000 0000 0010 10x 1614 | {0, 0x0022}, {0, 0x0021}, // 99: 0000 0000 0010 11x 1615 | {0, 0x0020}, {0, 0x010e}, // 100: 0000 0000 0011 00x 1616 | {0, 0x010d}, {0, 0x010c}, // 101: 0000 0000 0011 01x 1617 | {0, 0x010b}, {0, 0x010a}, // 102: 0000 0000 0011 10x 1618 | {0, 0x0109}, {0, 0x0108}, // 103: 0000 0000 0011 11x 1619 | {0, 0x0112}, {0, 0x0111}, // 104: 0000 0000 0001 000x 1620 | {0, 0x0110}, {0, 0x010f}, // 105: 0000 0000 0001 001x 1621 | {0, 0x0603}, {0, 0x1002}, // 106: 0000 0000 0001 010x 1622 | {0, 0x0f02}, {0, 0x0e02}, // 107: 0000 0000 0001 011x 1623 | {0, 0x0d02}, {0, 0x0c02}, // 108: 0000 0000 0001 100x 1624 | {0, 0x0b02}, {0, 0x1f01}, // 109: 0000 0000 0001 101x 1625 | {0, 0x1e01}, {0, 0x1d01}, // 110: 0000 0000 0001 110x 1626 | {0, 0x1c01}, {0, 0x1b01}, // 111: 0000 0000 0001 111x 1627 | } 1628 | --------------------------------------------------------------------------------