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