Shaka Packager SDK
id3_tag.cc
1 // Copyright 2018 Google LLC. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file or at
5 // https://developers.google.com/open-source/licenses/bsd
6 
7 #include <packager/media/base/id3_tag.h>
8 
9 #include <absl/log/log.h>
10 
11 #include <packager/media/base/buffer_writer.h>
12 #include <packager/media/base/fourccs.h>
13 
14 namespace shaka {
15 namespace media {
16 namespace {
17 
18 // ID3v2 header: http://id3.org/id3v2.4.0-structure.
19 const char kID3v2Identifier[] = "ID3";
20 const uint16_t kID3v2Version = 0x0400; // id3v2.4.0
21 
22 const uint32_t kMaxSynchsafeSize = 0x0FFFFFFF; // 28 effective bits.
23 
24 // Convert the specified size into synchsafe integer, where the most significant
25 // bit (bit 7) is set to zero in every byte.
26 uint32_t EncodeSynchsafe(uint32_t size) {
27  return (size & 0x7F) | (((size >> 7) & 0x7F) << 8) |
28  (((size >> 14) & 0x7F) << 16) | (((size >> 21) & 0x7F) << 24);
29 }
30 
31 bool WriteId3v2Header(uint32_t frames_size, BufferWriter* buffer_writer) {
32  buffer_writer->AppendString(kID3v2Identifier);
33  buffer_writer->AppendInt(kID3v2Version);
34  const uint8_t flags = 0;
35  buffer_writer->AppendInt(flags);
36 
37  if (frames_size > kMaxSynchsafeSize) {
38  LOG(ERROR) << "Input size (" << frames_size
39  << ") is out of range (> max synchsafe integer "
40  << kMaxSynchsafeSize << ").";
41  return false;
42  }
43  buffer_writer->AppendInt(EncodeSynchsafe(frames_size));
44 
45  return true;
46 }
47 
48 } // namespace
49 
50 void Id3Tag::AddPrivateFrame(const std::string& owner,
51  const std::string& data) {
52  private_frames_.push_back({owner, data});
53 }
54 
55 bool Id3Tag::WriteToBuffer(BufferWriter* buffer_writer) {
56  BufferWriter frames_buffer;
57  for (const PrivateFrame& private_frame : private_frames_) {
58  if (!WritePrivateFrame(private_frame, &frames_buffer))
59  return false;
60  }
61 
62  if (!WriteId3v2Header(frames_buffer.Size(), buffer_writer))
63  return false;
64  buffer_writer->AppendBuffer(frames_buffer);
65  return true;
66 }
67 
68 bool Id3Tag::WriteToVector(std::vector<uint8_t>* output) {
69  BufferWriter buffer_writer;
70  if (!WriteToBuffer(&buffer_writer))
71  return false;
72  buffer_writer.SwapBuffer(output);
73  return true;
74 }
75 
76 // Implemented per http://id3.org/id3v2.4.0-frames 4.27.
77 bool Id3Tag::WritePrivateFrame(const PrivateFrame& private_frame,
78  BufferWriter* buffer_writer) {
79  buffer_writer->AppendInt(static_cast<uint32_t>(FOURCC_PRIV));
80 
81  const uint32_t frame_size = static_cast<uint32_t>(
82  private_frame.owner.size() + 1 + private_frame.data.size());
83  if (frame_size > kMaxSynchsafeSize) {
84  LOG(ERROR) << "Input size (" << frame_size
85  << ") is out of range (> max synchsafe integer "
86  << kMaxSynchsafeSize << ").";
87  return false;
88  }
89  buffer_writer->AppendInt(EncodeSynchsafe(frame_size));
90 
91  const uint16_t flags = 0;
92  buffer_writer->AppendInt(flags);
93 
94  buffer_writer->AppendString(private_frame.owner);
95  uint8_t byte = 0; // NULL terminating byte between owner and value.
96  buffer_writer->AppendInt(byte);
97  buffer_writer->AppendString(private_frame.data);
98  return true;
99 }
100 
101 } // namespace media
102 } // namespace shaka
virtual bool WriteToBuffer(BufferWriter *buffer_writer)
Definition: id3_tag.cc:55
virtual void AddPrivateFrame(const std::string &owner, const std::string &data)
Definition: id3_tag.cc:50
virtual bool WriteToVector(std::vector< uint8_t > *output)
Definition: id3_tag.cc:68
All the methods that are virtual are virtual for mocking.
Definition: crypto_flags.cc:66