summaryrefslogtreecommitdiff
path: root/chromium/media/mp2t/ts_section_psi.cc
blob: f8a6fc310ce15284871da08a5870b6c5b2150dad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/mp2t/ts_section_psi.h"

#include "base/basictypes.h"
#include "base/logging.h"
#include "media/base/bit_reader.h"
#include "media/mp2t/mp2t_common.h"

static bool IsCrcValid(const uint8* buf, int size) {
  uint32 crc = 0xffffffffu;
  const uint32 kCrcPoly = 0x4c11db7;

  for (int k = 0; k < size; k++) {
    int nbits = 8;
    uint32 data_msb_aligned = buf[k];
    data_msb_aligned <<= (32 - nbits);

    while (nbits > 0) {
      if ((data_msb_aligned ^ crc) & 0x80000000) {
        crc <<= 1;
        crc ^= kCrcPoly;
      } else {
        crc <<= 1;
      }

      data_msb_aligned <<= 1;
      nbits--;
    }
  }

  return (crc == 0);
}

namespace media {
namespace mp2t {

TsSectionPsi::TsSectionPsi()
    : wait_for_pusi_(true),
      leading_bytes_to_discard_(0) {
}

TsSectionPsi::~TsSectionPsi() {
}

bool TsSectionPsi::Parse(bool payload_unit_start_indicator,
                             const uint8* buf, int size) {
  // Ignore partial PSI.
  if (wait_for_pusi_ && !payload_unit_start_indicator)
    return true;

  if (payload_unit_start_indicator) {
    // Reset the state of the PSI section.
    ResetPsiState();

    // Update the state.
    wait_for_pusi_ = false;
    DCHECK_GE(size, 1);
    int pointer_field = buf[0];
    leading_bytes_to_discard_ = pointer_field;
    buf++;
    size--;
  }

  // Discard some leading bytes if needed.
  if (leading_bytes_to_discard_ > 0) {
    int nbytes_to_discard = std::min(leading_bytes_to_discard_, size);
    buf += nbytes_to_discard;
    size -= nbytes_to_discard;
    leading_bytes_to_discard_ -= nbytes_to_discard;
  }
  if (size == 0)
    return true;

  // Add the data to the parser state.
  psi_byte_queue_.Push(buf, size);
  int raw_psi_size;
  const uint8* raw_psi;
  psi_byte_queue_.Peek(&raw_psi, &raw_psi_size);

  // Check whether we have enough data to start parsing.
  if (raw_psi_size < 3)
    return true;
  int section_length =
      ((static_cast<int>(raw_psi[1]) << 8) |
       (static_cast<int>(raw_psi[2]))) & 0xfff;
  if (section_length >= 1021)
    return false;
  int psi_length = section_length + 3;
  if (raw_psi_size < psi_length) {
    // Don't throw an error when there is not enough data,
    // just wait for more data to come.
    return true;
  }

  // There should not be any trailing bytes after a PMT.
  // Instead, the pointer field should be used to stuff bytes.
  DVLOG_IF(1, raw_psi_size > psi_length)
      << "Trailing bytes after a PSI section: "
      << psi_length << " vs " << raw_psi_size;

  // Verify the CRC.
  RCHECK(IsCrcValid(raw_psi, psi_length));

  // Parse the PSI section.
  BitReader bit_reader(raw_psi, raw_psi_size);
  bool status = ParsePsiSection(&bit_reader);
  if (status)
    ResetPsiState();

  return status;
}

void TsSectionPsi::Flush() {
}

void TsSectionPsi::Reset() {
  ResetPsiSection();
  ResetPsiState();
}

void TsSectionPsi::ResetPsiState() {
  wait_for_pusi_ = true;
  psi_byte_queue_.Reset();
  leading_bytes_to_discard_ = 0;
}

}  // namespace mp2t
}  // namespace media