Add Early Video Frame Flush

This commit is contained in:
Florian Märkl 2019-07-29 22:10:28 +02:00
commit ac87d622c8
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
7 changed files with 55 additions and 39 deletions

View file

@ -22,6 +22,7 @@
#include "takion.h"
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
@ -36,10 +37,10 @@ typedef struct chiaki_frame_processor_t
uint8_t *frame_buf;
size_t frame_buf_size;
size_t buf_size_per_unit;
unsigned int units_regular_expected;
unsigned int units_additional_expected;
unsigned int units_regular_received;
unsigned int units_additional_received;
unsigned int units_source_expected;
unsigned int units_fec_expected;
unsigned int units_source_received;
unsigned int units_fec_received;
ChiakiFrameUnit *unit_slots;
size_t unit_slots_size;
} ChiakiFrameProcessor;
@ -57,6 +58,12 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_frame_processor_alloc_frame(ChiakiFrameProc
CHIAKI_EXPORT ChiakiErrorCode chiaki_frame_processor_put_unit(ChiakiFrameProcessor *frame_processor, ChiakiTakionAVPacket *packet);
CHIAKI_EXPORT ChiakiFrameProcessorFlushResult chiaki_frame_processor_flush(ChiakiFrameProcessor *frame_processor, uint8_t **frame, size_t *frame_size);
static inline bool chiaki_frame_processor_flush_possible(ChiakiFrameProcessor *frame_processor)
{
return frame_processor->units_source_received //+ frame_processor->units_fec_received
>= frame_processor->units_source_expected;
}
#ifdef __cplusplus
}
#endif

View file

@ -50,8 +50,8 @@ typedef struct chiaki_takion_av_packet_t
bool uses_nalu_info_structs;
bool is_video;
ChiakiSeqNum16 unit_index;
uint16_t units_in_frame_total; // regular + units_in_frame_additional
uint16_t units_in_frame_additional;
uint16_t units_in_frame_total; // source + units_in_frame_fec
uint16_t units_in_frame_fec;
uint32_t codec;
uint16_t word_at_0x18;
uint8_t adaptive_stream_index;

View file

@ -36,8 +36,8 @@ CHIAKI_EXPORT void chiaki_frame_processor_init(ChiakiFrameProcessor *frame_proce
frame_processor->log = log;
frame_processor->frame_buf = NULL;
frame_processor->frame_buf_size = 0;
frame_processor->units_regular_expected = 0;
frame_processor->units_additional_expected = 0;
frame_processor->units_source_expected = 0;
frame_processor->units_fec_expected = 0;
frame_processor->unit_slots = NULL;
frame_processor->unit_slots_size = 0;
}
@ -50,19 +50,19 @@ CHIAKI_EXPORT void chiaki_frame_processor_fini(ChiakiFrameProcessor *frame_proce
CHIAKI_EXPORT ChiakiErrorCode chiaki_frame_processor_alloc_frame(ChiakiFrameProcessor *frame_processor, ChiakiTakionAVPacket *packet)
{
if(packet->units_in_frame_total < packet->units_in_frame_additional)
if(packet->units_in_frame_total < packet->units_in_frame_fec)
{
CHIAKI_LOGE(frame_processor->log, "Packet has units_in_frame_total < units_in_frame_additional");
CHIAKI_LOGE(frame_processor->log, "Packet has units_in_frame_total < units_in_frame_fec");
return CHIAKI_ERR_INVALID_DATA;
}
frame_processor->units_regular_expected = packet->units_in_frame_total - packet->units_in_frame_additional;
frame_processor->units_additional_expected = packet->units_in_frame_additional;
if(frame_processor->units_additional_expected < 1)
frame_processor->units_additional_expected = 1;
frame_processor->units_source_expected = packet->units_in_frame_total - packet->units_in_frame_fec;
frame_processor->units_fec_expected = packet->units_in_frame_fec;
if(frame_processor->units_fec_expected < 1)
frame_processor->units_fec_expected = 1;
frame_processor->buf_size_per_unit = packet->data_size;
if(packet->is_video && packet->unit_index < frame_processor->units_regular_expected)
if(packet->is_video && packet->unit_index < frame_processor->units_source_expected)
{
if(packet->data_size < 2)
{
@ -78,10 +78,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_frame_processor_alloc_frame(ChiakiFrameProc
return CHIAKI_ERR_BUF_TOO_SMALL;
}
frame_processor->units_regular_received = 0;
frame_processor->units_additional_received = 0;
frame_processor->units_source_received = 0;
frame_processor->units_fec_received = 0;
size_t unit_slots_size_required = frame_processor->units_regular_expected + frame_processor->units_additional_expected;
size_t unit_slots_size_required = frame_processor->units_source_expected + frame_processor->units_fec_expected;
if(unit_slots_size_required > UNIT_SLOTS_MAX)
{
CHIAKI_LOGE(frame_processor->log, "Packet suggests more than %u unit slots", UNIT_SLOTS_MAX);
@ -161,10 +161,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_frame_processor_put_unit(ChiakiFrameProcess
packet->data,
packet->data_size);
if(packet->unit_index < frame_processor->units_regular_expected)
frame_processor->units_regular_received++;
if(packet->unit_index < frame_processor->units_source_expected)
frame_processor->units_source_received++;
else
frame_processor->units_additional_received++;
frame_processor->units_fec_received++;
return CHIAKI_ERR_SUCCESS;
}
@ -175,18 +175,18 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_frame_processor_put_unit(ChiakiFrameProcess
static ChiakiErrorCode chiaki_frame_processor_fec(ChiakiFrameProcessor *frame_processor)
{
CHIAKI_LOGI(frame_processor->log, "Frame Processor received %u+%u / %u+%u units, attempting FEC",
frame_processor->units_regular_received, frame_processor->units_additional_received,
frame_processor->units_regular_expected, frame_processor->units_additional_expected);
frame_processor->units_source_received, frame_processor->units_fec_received,
frame_processor->units_source_expected, frame_processor->units_fec_expected);
size_t erasures_count = (frame_processor->units_regular_expected + frame_processor->units_additional_expected)
- (frame_processor->units_regular_received + frame_processor->units_additional_received);
size_t erasures_count = (frame_processor->units_source_expected + frame_processor->units_fec_expected)
- (frame_processor->units_source_received + frame_processor->units_fec_received);
unsigned int *erasures = calloc(erasures_count, sizeof(unsigned int));
if(!erasures)
return CHIAKI_ERR_MEMORY;
size_t erasure_index = 0;
for(size_t i=0; i<frame_processor->units_regular_expected + frame_processor->units_additional_expected; i++)
for(size_t i=0; i<frame_processor->units_source_expected + frame_processor->units_fec_expected; i++)
{
ChiakiFrameUnit *slot = frame_processor->unit_slots + i;
if(!slot->data_size)
@ -204,7 +204,7 @@ static ChiakiErrorCode chiaki_frame_processor_fec(ChiakiFrameProcessor *frame_pr
assert(erasure_index == erasures_count);
ChiakiErrorCode err = chiaki_fec_decode(frame_processor->frame_buf, frame_processor->buf_size_per_unit,
frame_processor->units_regular_expected, frame_processor->units_additional_received,
frame_processor->units_source_expected, frame_processor->units_fec_received,
erasures, erasures_count);
if(err != CHIAKI_ERR_SUCCESS)
@ -218,7 +218,7 @@ static ChiakiErrorCode chiaki_frame_processor_fec(ChiakiFrameProcessor *frame_pr
CHIAKI_LOGI(frame_processor->log, "FEC successful");
// restore unit sizes
for(size_t i=0; i<frame_processor->units_regular_expected; i++)
for(size_t i=0; i<frame_processor->units_source_expected; i++)
{
ChiakiFrameUnit *slot = frame_processor->unit_slots + i;
uint8_t *buf_ptr = frame_processor->frame_buf + frame_processor->buf_size_per_unit * i;
@ -240,10 +240,10 @@ static ChiakiErrorCode chiaki_frame_processor_fec(ChiakiFrameProcessor *frame_pr
CHIAKI_EXPORT ChiakiFrameProcessorFlushResult chiaki_frame_processor_flush(ChiakiFrameProcessor *frame_processor, uint8_t **frame, size_t *frame_size)
{
if(frame_processor->units_regular_expected == 0)
if(frame_processor->units_source_expected == 0)
return CHIAKI_FRAME_PROCESSOR_FLUSH_RESULT_FAILED;
if(frame_processor->units_regular_received < frame_processor->units_regular_expected)
if(frame_processor->units_source_received < frame_processor->units_source_expected)
{
ChiakiErrorCode err = chiaki_frame_processor_fec(frame_processor);
if(err != CHIAKI_ERR_SUCCESS)
@ -255,7 +255,7 @@ CHIAKI_EXPORT ChiakiFrameProcessorFlushResult chiaki_frame_processor_flush(Chiak
return CHIAKI_FRAME_PROCESSOR_FLUSH_RESULT_FAILED;
size_t buf_size = 0;
for(size_t i=0; i<frame_processor->units_regular_expected; i++)
for(size_t i=0; i<frame_processor->units_source_expected; i++)
{
ChiakiFrameUnit *unit = frame_processor->unit_slots + i;
if(unit->data_size < 2)

View file

@ -706,7 +706,7 @@ static void stream_connection_takion_av(ChiakiStreamConnection *stream_connectio
chiaki_gkcrypt_decrypt(stream_connection->gkcrypt_remote, packet->key_pos + CHIAKI_GKCRYPT_BLOCK_SIZE, packet->data, packet->data_size);
/*CHIAKI_LOGD(stream_connection->log, "AV: index: %u,%u; b@0x1a: %d; is_video: %d; 0xa: %u; 0xc: %u; 0xe: %u; codec: %u; 0x18: %u; adaptive_stream: %u, 0x2c: %u",
header->packet_index, header->frame_index, header->byte_at_0x1a, header->is_video ? 1 : 0, header->word_at_0xa, header->units_in_frame_total, header->units_in_frame_additional, header->codec,
header->packet_index, header->frame_index, header->byte_at_0x1a, header->is_video ? 1 : 0, header->word_at_0xa, header->units_in_frame_total, header->units_in_frame_fec, header->codec,
header->word_at_0x18, header->adaptive_stream_index, header->byte_at_0x2c);
chiaki_log_hexdump(stream_connection->log, CHIAKI_LOG_DEBUG, buf, buf_size);*/

View file

@ -1146,13 +1146,13 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_av_packet_parse(ChiakiTakionAVPacket
{
packet->unit_index = (uint16_t)((dword_2 >> 0x15) & 0x7ff);
packet->units_in_frame_total = (uint16_t)(((dword_2 >> 0xa) & 0x7ff) + 1);
packet->units_in_frame_additional = (uint16_t)(dword_2 & 0x3ff);
packet->units_in_frame_fec = (uint16_t)(dword_2 & 0x3ff);
}
else
{
packet->unit_index = (uint16_t)((dword_2 >> 0x18) & 0xff);
packet->units_in_frame_total = (uint16_t)(((dword_2 >> 0x10) & 0xff) + 1);
packet->units_in_frame_additional = (uint16_t)(dword_2 & 0xffff);
packet->units_in_frame_fec = (uint16_t)(dword_2 & 0xffff);
}
packet->codec = av[8];

View file

@ -20,7 +20,7 @@
#include <string.h>
static void chiaki_video_receiver_flush_frame(ChiakiVideoReceiver *video_receiver);
static ChiakiErrorCode chiaki_video_receiver_flush_frame(ChiakiVideoReceiver *video_receiver);
CHIAKI_EXPORT void chiaki_video_receiver_init(ChiakiVideoReceiver *video_receiver, struct chiaki_session_t *session)
{
@ -111,10 +111,18 @@ CHIAKI_EXPORT void chiaki_video_receiver_av_packet(ChiakiVideoReceiver *video_re
chiaki_frame_processor_alloc_frame(&video_receiver->frame_processor, packet);
}
chiaki_frame_processor_put_unit(&video_receiver->frame_processor, packet);
// if we are currently building up a frame
if(video_receiver->frame_index_cur != video_receiver->frame_index_prev)
{
chiaki_frame_processor_put_unit(&video_receiver->frame_processor, packet);
// if we already have enough for the whole frame, flush it already
if(chiaki_frame_processor_flush_possible(&video_receiver->frame_processor))
chiaki_video_receiver_flush_frame(video_receiver);
}
}
static void chiaki_video_receiver_flush_frame(ChiakiVideoReceiver *video_receiver)
static ChiakiErrorCode chiaki_video_receiver_flush_frame(ChiakiVideoReceiver *video_receiver)
{
uint8_t *frame;
size_t frame_size;
@ -124,11 +132,12 @@ static void chiaki_video_receiver_flush_frame(ChiakiVideoReceiver *video_receive
{
// TODO: fake frame?
CHIAKI_LOGW(video_receiver->log, "Failed to complete frame %d", (int)video_receiver->frame_index_cur);
return;
return CHIAKI_ERR_UNKNOWN;
}
if(video_receiver->session->video_sample_cb)
video_receiver->session->video_sample_cb(frame, frame_size, video_receiver->session->video_sample_cb_user);
free(frame);
video_receiver->frame_index_prev = video_receiver->frame_index_cur;
return CHIAKI_ERR_SUCCESS;
}

View file

@ -48,7 +48,7 @@ static MunitResult test_av_packet_parse(const MunitParameter params[], void *use
// TODO: uses_nalu_info_structs
munit_assert_uint16(av_packet.unit_index, ==, 6);
munit_assert_uint16(av_packet.units_in_frame_total, ==, 8);
munit_assert_uint16(av_packet.units_in_frame_additional, ==, 1);
munit_assert_uint16(av_packet.units_in_frame_fec, ==, 1);
munit_assert_uint32(av_packet.codec, ==, 3);
// munit_assert_uint16(av_packet.word_at_0x18, ==, 871);
munit_assert_uint8(av_packet.adaptive_stream_index, ==, 0);