Shaka Packager SDK
Loading...
Searching...
No Matches
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
14namespace shaka {
15namespace media {
16namespace {
17
18// ID3v2 header: http://id3.org/id3v2.4.0-structure.
19const char kID3v2Identifier[] = "ID3";
20const uint16_t kID3v2Version = 0x0400; // id3v2.4.0
21
22const 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.
26uint32_t EncodeSynchsafe(uint32_t size) {
27 return (size & 0x7F) | (((size >> 7) & 0x7F) << 8) |
28 (((size >> 14) & 0x7F) << 16) | (((size >> 21) & 0x7F) << 24);
29}
30
31bool 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
50void Id3Tag::AddPrivateFrame(const std::string& owner,
51 const std::string& data) {
52 private_frames_.push_back({owner, data});
53}
54
55bool 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
68bool 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.
77bool 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.