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