93 LOGI(
"Starting JPEG RTP Encoder");
102 LOGI(
"Stopping JPEG RTP Encoder");
114 const char *
mime()
override {
return "video/jpeg"; }
123 size_t write(
const uint8_t *data,
size_t len)
override {
167 if (size < 4)
return false;
180 if (size < 4)
return 0;
181 for (
size_t i = 0; i + 4 <= size; i++) {
184 size_t dataStart = i + 2 + sosLength;
185 return dataStart <= size ? dataStart : 0;
211 bool has0 =
false, has1 =
false;
214 while (i + 4 <= headerLen) {
215 if (data[i] != 0xFF) {
219 uint8_t marker = data[i + 1];
220 if (marker == 0xD8 || marker == 0x01 || (marker >= 0xD0 && marker <= 0xD7)) {
224 size_t segLen = (data[i + 2] << 8) | data[i + 3];
225 if (segLen < 2 || i + 2 + segLen > headerLen)
break;
227 if (marker == 0xDB) {
229 size_t segEnd = i + 2 + segLen;
231 uint8_t pqtq = data[p++];
232 uint8_t precision = pqtq >> 4;
233 uint8_t
id = pqtq & 0x0F;
234 size_t tableBytes = precision == 0 ? 64 : 128;
235 if (p + tableBytes > segEnd)
break;
236 if (precision == 0) {
237 if (
id == 0 && !has0) {
238 memcpy(table0, data + p, 64);
240 }
else if (
id == 1 && !has1) {
241 memcpy(table1, data + p, 64);
247 }
else if (marker == 0xDA) {
254 memcpy(out, table0, 64);
255 memcpy(out + 64, has1 ? table1 : table0, 64);
266 while (i + 4 <= headerLen) {
267 if (data[i] != 0xFF) {
271 uint8_t marker = data[i + 1];
272 if (marker == 0xD8 || marker == 0x01 || (marker >= 0xD0 && marker <= 0xD7)) {
276 size_t segLen = (data[i + 2] << 8) | data[i + 3];
277 if (segLen < 2 || i + 2 + segLen > headerLen)
break;
279 if (marker == 0xC0 || marker == 0xC1) {
281 size_t segEnd = i + 2 + segLen;
283 if (p + 8 <= segEnd) {
284 uint8_t hv = data[p + 7];
286 uint8_t v = hv & 0x0F;
287 if (h == 2 && v == 1)
return 0;
288 if (h == 2 && v == 2)
return 1;
290 "JPEGRtpEncoder: unsupported chroma subsampling H=%d V=%d; "
296 if (marker == 0xDA)
break;
299 LOGW(
"JPEGRtpEncoder: SOF0 marker not found; assuming 4:2:2 subsampling");
304 int height, uint8_t type, uint8_t qValue) {
306 buffer[1] = (fragmentOffset >> 16) & 0xFF;
307 buffer[2] = (fragmentOffset >> 8) & 0xFF;
308 buffer[3] = fragmentOffset & 0xFF;
311 buffer[6] = (uint8_t)((width / 8) & 0xFF);
312 buffer[7] = (uint8_t)((height / 8) & 0xFF);
320 buffer[2] = (qTableLen >> 8) & 0xFF;
321 buffer[3] = qTableLen & 0xFF;
322 memcpy(buffer + 4, qTable, qTableLen);
331 LOGE(
"JPEGRtpEncoder: no RTSPFormat configured (call setFormat()); dropping frame");
337 LOGW(
"JPEGRtpEncoder: could not locate JPEG scan data (SOS marker); dropping frame");
343 uint8_t qValue = qTableLen > 0 ? 255 : 127;
344 if (qTableLen == 0) {
346 "JPEGRtpEncoder: could not extract quantization tables from frame; "
347 "using approximate standard tables (Q=%d)",
353 int width = vi.
width;
358 size_t processedOffset = 0;
359 int fragmentCount = 0;
362 bool isFirst = (processedOffset == 0);
363 size_t qLen = isFirst ? (size_t)qTableLen : 0;
364 size_t qHeaderLen = qLen > 0 ? 4 + qLen : 0;
367 LOGE(
"JPEGRtpEncoder: maxFragmentSize too small to fit RTP/JPEG headers");
371 size_t chunk =
frameSize - processedOffset;
372 if (chunk > maxData) chunk = maxData;
373 bool isLast = (processedOffset + chunk >=
frameSize);
377 if (qHeaderLen > 0) {
380 memcpy(
m_scratch.
data() + 8 + qHeaderLen, frameData + processedOffset, chunk);
384 processedOffset += chunk;
388 LOGI(
"JPEGRtpEncoder: queued %d RTP fragments for %u byte frame",
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define LOGI(...)
Definition AudioLoggerIDF.h:28
#define LOGE(...)
Definition AudioLoggerIDF.h:30