1 #include "opus-ogg.hpp"
3 #include "serialization.hpp"
8 void ogg_header::parse(struct ogg::packet
& packet
) throw(std::runtime_error
)
11 if(!packet
.get_atomic())
12 throw std::runtime_error("OggOpus header page must have one complete packet");
13 if(packet
.get_granulepos() != 0)
14 throw std::runtime_error("OggOpus header page must have granulepos 0");
15 if(!packet
.get_on_bos_page() || packet
.get_on_eos_page())
16 throw std::runtime_error("OggOpus header page must be first but not last page");
17 const std::vector
<uint8_t>& p
= packet
.get_vector();
18 if(p
.size() < 9 || memcmp(&p
[0], "OpusHead", 8))
19 throw std::runtime_error("Bad OggOpus header magic");
21 throw std::runtime_error("Unsupported OggOpus version");
22 if(p
.size() < 19 || (p
[18] && p
.size() < 21U + p
[9]))
23 throw std::runtime_error("OggOpus header packet truncated");
25 throw std::runtime_error("Zero channels not allowed");
28 h
.preskip
= serialization::u16l(&p
[10]);
29 h
.rate
= serialization::u32l(&p
[12]);
30 h
.gain
= serialization::s16l(&p
[16]);
32 memset(h
.chanmap
, 255, sizeof(h
.chanmap
));
36 if(h
.coupled
> h
.streams
)
37 throw std::runtime_error("More coupled streams than total streams.");
38 if(static_cast<int>(h
.streams
) > 255 - h
.coupled
)
39 throw std::runtime_error("Maximum of 255 physical channels exceeded");
40 memcpy(h
.chanmap
, &p
[21], h
.channels
);
41 for(unsigned i
= 0; i
< h
.channels
; i
++)
42 if(h
.chanmap
[i
] != 255 && h
.chanmap
[i
] > h
.streams
+ h
.coupled
)
43 throw std::runtime_error("Logical channel mapped to invalid physical channel");
47 throw std::runtime_error("Only 1 or 2 channels allowed with mapping family 0");
48 h
.coupled
= (h
.channels
== 2) ? 1 : 0;
50 if(h
.channels
== 2) h
.chanmap
[1] = 1;
55 void ogg_tags::parse(struct ogg::packet
& packet
) throw(std::bad_alloc
, std::runtime_error
)
58 if(!packet
.get_first_page() || !packet
.get_last_page())
59 throw std::runtime_error("OggOpus tags packet must be alone on its pages");
60 if(packet
.get_granulepos() != 0)
61 throw std::runtime_error("OggOpus header page must have granulepos 0");
62 if(packet
.get_on_bos_page())
63 throw std::runtime_error("OggOpus tags page must not be first page");
64 const std::vector
<uint8_t>& p
= packet
.get_vector();
65 if(p
.size() < 8 || memcmp(&p
[0], "OpusTags", 8))
66 throw std::runtime_error("Bad OggOpus tags magic");
68 throw std::runtime_error("OggOpus header packet truncated");
72 itr
= itr
+ 4 + serialization::u32l(&p
[itr
]);
73 if(itr
+ 4 > p
.size())
74 throw std::runtime_error("OggOpus header packet truncated");
75 h
.vendor
= std::string(&p
[oitr
+ 4], &p
[itr
]);
76 if(itr
+ 4 > p
.size())
77 throw std::runtime_error("OggOpus header packet truncated");
78 uint32_t headers
= serialization::u32l(&p
[itr
]);
80 for(uint32_t i
= 0; i
< headers
; i
++) {
81 if(itr
+ 4 > p
.size())
82 throw std::runtime_error("OggOpus header packet truncated");
83 itr
= itr
+ 4 + serialization::u32l(&p
[itr
]);
85 throw std::runtime_error("OggOpus header packet truncated");
86 h
.comments
.push_back(std::string(&p
[oitr
+ 4], &p
[itr
]));
92 ogg::page
ogg_header::serialize() throw(std::runtime_error
)
94 struct ogg::page page
;
95 unsigned char buffer
[276];
98 throw std::runtime_error("Don't how to serialize this oggopus version");
99 if(!channels
|| (channels
> 2 && !map_family
))
100 throw std::runtime_error("Illegal channel count");
101 if(map_family
&& static_cast<int>(streams
) > 255 - coupled
)
102 throw std::runtime_error("Maximum of 255 physical channels exceeded");
104 for(unsigned i
= 0; i
< channels
; i
++)
105 if(chanmap
[i
] != 255 && chanmap
[i
] > streams
+ coupled
)
106 throw std::runtime_error("Logical channel mapped to invalid physical channel");
107 serialization::u64b(buffer
, 0x4F70757348656164ULL
);
109 buffer
[9] = channels
;
110 serialization::u16l(buffer
+ 10, preskip
);
111 serialization::u32l(buffer
+ 12, rate
);
112 serialization::s16l(buffer
+ 16, gain
);
113 buffer
[18] = map_family
;
115 buffer
[19] = streams
;
116 buffer
[20] = coupled
;
117 memcpy(buffer
+ 21, chanmap
, channels
);
118 bsize
= 21 + channels
;
121 if(!page
.append_packet(buffer
, bsize
))
122 throw std::runtime_error("Header packet too large");
123 page
.set_granulepos(0);
124 page
.set_sequence(0);
129 uint32_t ogg_tags::serialize(std::function
<void(const ogg::page
& p
)> output
,
130 uint32_t strmid
) throw(std::bad_alloc
, std::runtime_error
)
133 needed
+= vendor
.length();
135 for(auto i
: comments
)
136 needed
+= (i
.length() + 4);
138 //TODO: Do without this buffer.
139 std::vector
<uint8_t> contents
;
140 contents
.resize(needed
);
142 serialization::u64b(&contents
[0], 0x4F70757354616773ULL
);
143 serialization::u32l(&contents
[8], vendor
.length());
144 std::copy(vendor
.begin(), vendor
.end(), reinterpret_cast<char*>(&contents
[12]));
145 itr
= 12 + vendor
.length();
146 serialization::u32l(&contents
[itr
], comments
.size());
148 for(auto i
: comments
) {
149 serialization::u32l(&contents
[itr
], i
.length());
150 std::copy(i
.begin(), i
.end(), reinterpret_cast<char*>(&contents
[itr
+ 4]));
151 itr
+= (i
.length() + 4);
154 uint32_t next_page
= 1;
158 q
.set_continue(next_page
!= 1);
162 q
.set_stream(strmid
);
163 q
.set_sequence(next_page
++);
164 const uint8_t* ptr
= &contents
[written
];
165 size_t szr
= needed
- written
;
166 bool complete
= q
.append_packet_incomplete(ptr
, szr
);
170 written
= ptr
- &contents
[0];