flutter_fc_media 0.0.8
flutter_fc_media: ^0.0.8 copied to clipboard
FC 视频解析插件 RTP --> RTSP.
0.0.1 #
- 首版更新
- 上传到 pub.dev
flutter pub publish --dry-run,flutter pub publish --server=https://pub.dartlang.org
- 上传到 pub.dev
0.0.2 #
- 项目更新 api, 可以监听指定端口的数据
0.0.3 #
- 修复问题
0.0.4 #
- 修改 ZLMediakit 相关信息
- 修改
DRI判断, 以及对应的0x40相关逻辑
* 新增内容
uint16_t restart_interval = 0;
else if (buf[i + 1] == DRI) {
type |= 0x40;
restart_interval = AV_RB16(&buf[i + 4]);
}
if (type & 0x40)
hdr_size += 4;
if (type & 0x40) {
bytestream_put_be16(&p,restart_interval);
bytestream_put_byte(&p,0xff);
bytestream_put_byte(&p, 0xff);
}
void JPEGRtpEncoder::rtpSendJpeg(const uint8_t *buf, int size, uint64_t pts, uint8_t type)
{
const uint8_t *qtables[4] = { NULL };
int nb_qtables = 0;
uint8_t w, h;
uint8_t *p;
int off = 0; /* fragment offset of the current JPEG frame */
int len;
int i;
int default_huffman_tables = 0;
uint8_t *out = nullptr;
uint16_t restart_interval = 0;
/* preparse the header for getting some info */
for (i = 0; i < size; i++) {
if (buf[i] != 0xff)
continue;
if (buf[i + 1] == DQT) {
int tables, j;
if (buf[i + 4] & 0xF0)
av_log(s1, AV_LOG_WARNING,
"Only 8-bit precision is supported.\n");
/* a quantization table is 64 bytes long */
tables = AV_RB16(&buf[i + 2]) / 65;
if (i + 5 + tables * 65 > size) {
av_log(s1, AV_LOG_ERROR, "Too short JPEG header. Aborted!\n");
return;
}
if (nb_qtables + tables > 4) {
av_log(s1, AV_LOG_ERROR, "Invalid number of quantisation tables\n");
return;
}
for (j = 0; j < tables; j++)
qtables[nb_qtables + j] = buf + i + 5 + j * 65;
nb_qtables += tables;
// 大致忽略DQT/qtable所占字节数,提高搜寻速度
i += tables << 6;
} else if (buf[i + 1] == SOF0) {
if (buf[i + 14] != 17 || buf[i + 17] != 17) {
av_log(s1, AV_LOG_ERROR,
"Only 1x1 chroma blocks are supported. Aborted!\n");
return;
}
h = (buf[i + 5] * 256 + buf[i + 6]) / 8;
w = (buf[i + 7] * 256 + buf[i + 8]) / 8;
// 大致忽略SOF0所占字节数,提高搜寻速度
i += 16;
} else if (buf[i + 1] == DHT) {
int dht_size = AV_RB16(&buf[i + 2]);
default_huffman_tables |= 1 << 4;
i += 3;
dht_size -= 2;
if (i + dht_size >= size)
continue;
while (dht_size > 0)
switch (buf[i + 1]) {
case 0x00:
if ( dht_size >= 29
&& !memcmp(buf + i + 2, avpriv_mjpeg_bits_dc_luminance + 1, 16)
&& !memcmp(buf + i + 18, avpriv_mjpeg_val_dc, 12)) {
default_huffman_tables |= 1;
i += 29;
dht_size -= 29;
} else {
i += dht_size;
dht_size = 0;
}
break;
case 0x01:
if ( dht_size >= 29
&& !memcmp(buf + i + 2, avpriv_mjpeg_bits_dc_chrominance + 1, 16)
&& !memcmp(buf + i + 18, avpriv_mjpeg_val_dc, 12)) {
default_huffman_tables |= 1 << 1;
i += 29;
dht_size -= 29;
} else {
i += dht_size;
dht_size = 0;
}
break;
case 0x10:
if ( dht_size >= 179
&& !memcmp(buf + i + 2, avpriv_mjpeg_bits_ac_luminance + 1, 16)
&& !memcmp(buf + i + 18, avpriv_mjpeg_val_ac_luminance, 162)) {
default_huffman_tables |= 1 << 2;
i += 179;
dht_size -= 179;
} else {
i += dht_size;
dht_size = 0;
}
break;
case 0x11:
if ( dht_size >= 179
&& !memcmp(buf + i + 2, avpriv_mjpeg_bits_ac_chrominance + 1, 16)
&& !memcmp(buf + i + 18, avpriv_mjpeg_val_ac_chrominance, 162)) {
default_huffman_tables |= 1 << 3;
i += 179;
dht_size -= 179;
} else {
i += dht_size;
dht_size = 0;
}
break;
default:
i += dht_size;
dht_size = 0;
continue;
}
} else if (buf[i + 1] == SOS) {
/* SOS is last marker in the header */
i += AV_RB16(&buf[i + 2]) + 2;
if (i > size) {
av_log(s1, AV_LOG_ERROR,
"Insufficient data. Aborted!\n");
return;
}
break;
} else if (buf[i + 1] == DRI) {
type |= 0x40;
restart_interval = AV_RB16(&buf[i + 4]);
}
}
if (default_huffman_tables && default_huffman_tables != 31) {
av_log(s1, AV_LOG_ERROR,
"RFC 2435 requires standard Huffman tables for jpeg\n");
return;
}
if (nb_qtables && nb_qtables != 2)
av_log(s1, AV_LOG_WARNING,
"RFC 2435 suggests two quantization tables, %d provided\n",
nb_qtables);
/* skip JPEG header */
buf += i;
size -= i;
for (i = size - 2; i >= 0; i--) {
if (buf[i] == 0xff && buf[i + 1] == EOI) {
/* Remove the EOI marker */
size = i;
break;
}
}
while (size > 0) {
int hdr_size = 8;
if (off == 0 && nb_qtables)
hdr_size += 4 + 64 * nb_qtables;
if (type & 0x40)
hdr_size += 4;
/* payload max in one packet */
len = MIN(size, (int)getRtpInfo().getMaxSize() - hdr_size);
/* marker bit is last packet in frame */
auto rtp_packet = getRtpInfo().makeRtp(TrackVideo, nullptr, len + hdr_size, size == len, pts);
p = rtp_packet->getPayload();
/* set main header */
bytestream_put_byte(&p, 0);
bytestream_put_be24(&p, off);
bytestream_put_byte(&p, type);
bytestream_put_byte(&p, 255);
bytestream_put_byte(&p, w);
bytestream_put_byte(&p, h);
if (type & 0x40) {
bytestream_put_be16(&p,restart_interval);
bytestream_put_byte(&p,0xff);
bytestream_put_byte(&p, 0xff);
}
if (off == 0 && nb_qtables) {
/* set quantization tables header */
bytestream_put_byte(&p, 0);
bytestream_put_byte(&p, 0);
bytestream_put_be16(&p, 64 * nb_qtables);
for (i = 0; i < nb_qtables; i++)
bytestream_put_buffer(&p, qtables[i], 64);
}
/* copy payload data */
memcpy(p, buf, len);
// output rtp packet
RtpCodec::inputRtp(std::move(rtp_packet), false);
buf += len;
size -= len;
off += len;
}
free(out);
}
0.0.5 #
- 添加 Android 版本
0.0.6 #
- 添加 Android 视频解析功能
0.0.8 #
- Android 版本优化