Commit a45747af authored by Ghislain MARY's avatar Ghislain MARY

Handle sending and receiving of SLI messages for VP8 streams.

parent 516734d4
......@@ -515,6 +515,31 @@ static int enc_notify_fir(MSFilter *f, void *data) {
return 0;
}
static int enc_notify_sli(MSFilter *f, void *data) {
EncState *s = (EncState *)f->data;
MSVideoCodecSLI *sli = (MSVideoCodecSLI *)data;
bool_t golden_lost = FALSE;
bool_t altref_lost = FALSE;
if ((s->frames_state.golden.picture_id & 0x3F) == sli->picture_id) {
/* Last golden frame has been lost. */
golden_lost = TRUE;
}
if ((s->frames_state.altref.picture_id & 0x3F) == sli->picture_id) {
/* Last altref frame has been lost. */
altref_lost = TRUE;
}
if ((golden_lost == TRUE) && (altref_lost == TRUE)) {
/* Last key frame has been lost. */
s->force_keyframe = TRUE;
} else if (golden_lost == TRUE) {
// TODO: Generate golden frame
} else if (altref_lost == TRUE) {
// TODO: Generate altref frame
}
return 0;
}
static int enc_notify_rpsi(MSFilter *f, void *data) {
EncState *s = (EncState *)f->data;
MSVideoCodecRPSI *rpsi = (MSVideoCodecRPSI *)data;
......@@ -556,6 +581,7 @@ static MSFilterMethod enc_methods[] = {
{ MS_VIDEO_ENCODER_REQ_VFU, enc_req_vfu },
{ MS_VIDEO_ENCODER_NOTIFY_PLI, enc_notify_pli },
{ MS_VIDEO_ENCODER_NOTIFY_FIR, enc_notify_fir },
{ MS_VIDEO_ENCODER_NOTIFY_SLI, enc_notify_sli },
{ MS_VIDEO_ENCODER_NOTIFY_RPSI, enc_notify_rpsi },
{ MS_VIDEO_ENCODER_GET_CONFIGURATION_LIST, enc_get_configuration_list },
{ MS_VIDEO_ENCODER_SET_CONFIGURATION, enc_set_configuration },
......
......@@ -136,6 +136,87 @@ static int cseq_compare(const void *d1, const void *d2) {
return (p1->extended_cseq > p2->extended_cseq);
}
static bool_t is_key_frame(Vp8RtpFmtFrame *frame) {
Vp8RtpFmtPartition *partition;
int nb_partitions = ms_list_size(frame->partitions_list);
if (nb_partitions < 1) return FALSE;
partition = (Vp8RtpFmtPartition *)ms_list_nth_data(frame->partitions_list, 0);
if (partition->m->b_rptr[0] & 0x01) return FALSE;
return TRUE;
}
static bool_t is_reference_frame(Vp8RtpFmtFrame *frame, Vp8RtpFmtPayloadDescriptor **pd) {
Vp8RtpFmtPartition *partition;
Vp8RtpFmtPacket *packet;
int nb_packets;
int nb_partitions = ms_list_size(frame->partitions_list);
if (nb_partitions < 1) return FALSE;
partition = (Vp8RtpFmtPartition *)ms_list_nth_data(frame->partitions_list, 0);
nb_packets = ms_list_size(partition->packets_list);
if (nb_packets < 1) return FALSE;
packet = (Vp8RtpFmtPacket *)ms_list_nth_data(partition->packets_list, 0);
if (packet->pd->non_reference_frame == TRUE) {
return FALSE;
} else {
*pd = packet->pd;
return TRUE;
}
}
static MSVideoSize get_size_from_key_frame(Vp8RtpFmtFrame *frame) {
MSVideoSize vs;
Vp8RtpFmtPartition *partition = (Vp8RtpFmtPartition *)ms_list_nth_data(frame->partitions_list, 0);
vs.width = ((partition->m->b_rptr[7] << 8) | (partition->m->b_rptr[6])) & 0x3FFF;
vs.height = ((partition->m->b_rptr[9] << 8) | (partition->m->b_rptr[8])) & 0x3FFF;
return vs;
}
static void send_pli(Vp8RtpFmtUnpackerCtx *ctx) {
if (ctx->avpf_enabled == TRUE) {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
} else {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
}
}
static void send_sli_if_reference_frame(Vp8RtpFmtUnpackerCtx *ctx, Vp8RtpFmtFrame *frame) {
Vp8RtpFmtPayloadDescriptor *pd;
if (ctx->avpf_enabled == TRUE) {
if (is_reference_frame(frame, &pd) && (pd->pictureid_present == TRUE)) {
MSVideoCodecSLI sli;
sli.first = 0;
sli.number = (ctx->video_size.width * ctx->video_size.height) / (16 * 16);
sli.picture_id = pd->pictureid & 0x3F;
ms_filter_notify(ctx->filter, MS_VIDEO_DECODER_SEND_SLI, &sli);
}
} else {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
}
}
static void send_rpsi_if_reference_frame(Vp8RtpFmtUnpackerCtx *ctx, Vp8RtpFmtFrame *frame) {
Vp8RtpFmtPayloadDescriptor *pd;
if (ctx->avpf_enabled == TRUE) {
if (is_reference_frame(frame, &pd) && (pd->pictureid_present == TRUE)) {
MSVideoCodecRPSI rpsi;
uint16_t picture_id16;
uint8_t picture_id8;
if (pd->pictureid & 0x8000) {
picture_id16 = htons(pd->pictureid);
rpsi.bit_string = (uint8_t *)&picture_id16;
rpsi.bit_string_len = 16;
} else {
picture_id8 = pd->pictureid & 0xFF;
rpsi.bit_string = (uint8_t *)&picture_id8;
rpsi.bit_string_len = 8;
}
ms_filter_notify(ctx->filter, MS_VIDEO_DECODER_SEND_RPSI, &rpsi);
}
}
}
static void add_partition_to_frame(Vp8RtpFmtFrame *frame, Vp8RtpFmtPartition *partition) {
Vp8RtpFmtPacket *packet;
int nb_packets;
......@@ -248,11 +329,7 @@ static void add_frame(Vp8RtpFmtUnpackerCtx *ctx, MSList **packets_list) {
/* There are no valid partitions in the frame. */
ms_warning("VP8 frame without any valid partition.");
ms_free(frame);
if (ctx->avpf_enabled == TRUE) {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
} else {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
}
send_pli(ctx);
}
}
ms_list_free(*packets_list);
......@@ -326,37 +403,9 @@ static void output_frame(MSQueue *out, Vp8RtpFmtFrame *frame) {
}
}
static bool_t is_key_frame(Vp8RtpFmtFrame *frame) {
Vp8RtpFmtPartition *partition;
int nb_partitions = ms_list_size(frame->partitions_list);
if (nb_partitions < 1) return FALSE;
partition = (Vp8RtpFmtPartition *)ms_list_nth_data(frame->partitions_list, 0);
if (partition->m->b_rptr[0] & 0x01) return FALSE;
return TRUE;
}
static bool_t is_reference_frame(Vp8RtpFmtFrame *frame, Vp8RtpFmtPayloadDescriptor **pd) {
Vp8RtpFmtPartition *partition;
Vp8RtpFmtPacket *packet;
int nb_packets;
int nb_partitions = ms_list_size(frame->partitions_list);
if (nb_partitions < 1) return FALSE;
partition = (Vp8RtpFmtPartition *)ms_list_nth_data(frame->partitions_list, 0);
nb_packets = ms_list_size(partition->packets_list);
if (nb_packets < 1) return FALSE;
packet = (Vp8RtpFmtPacket *)ms_list_nth_data(partition->packets_list, 0);
if (packet->pd->non_reference_frame == TRUE) {
return FALSE;
} else {
*pd = packet->pd;
return TRUE;
}
}
static void output_valid_partitions(Vp8RtpFmtUnpackerCtx *ctx, MSQueue *out) {
Vp8RtpFmtPartition *partition = NULL;
Vp8RtpFmtFrame *frame;
Vp8RtpFmtPayloadDescriptor *pd;
int nb_frames = ms_list_size(ctx->frames_list);
int nb_partitions;
int i;
......@@ -367,6 +416,7 @@ static void output_valid_partitions(Vp8RtpFmtUnpackerCtx *ctx, MSQueue *out) {
if (frame->error == Vp8RtpFmtOk) {
if (is_key_frame(frame) == TRUE) {
ctx->valid_keyframe_received = TRUE;
ctx->video_size = get_size_from_key_frame(frame);
}
if (ctx->valid_keyframe_received == TRUE) {
/* Output the complete valid frame if the first keyframe has been received. */
......@@ -381,32 +431,12 @@ static void output_valid_partitions(Vp8RtpFmtUnpackerCtx *ctx, MSQueue *out) {
output_frame(out, frame);
}
frame->outputted = TRUE;
if (is_reference_frame(frame, &pd)) {
if (pd->pictureid_present == TRUE) {
MSVideoCodecRPSI rpsi;
uint16_t picture_id16;
uint8_t picture_id8;
if (pd->pictureid & 0x8000) {
picture_id16 = htons(pd->pictureid);
rpsi.bit_string = (uint8_t *)&picture_id16;
rpsi.bit_string_len = 16;
} else {
picture_id8 = pd->pictureid & 0xFF;
rpsi.bit_string = (uint8_t *)&picture_id8;
rpsi.bit_string_len = 8;
}
ms_filter_notify(ctx->filter, MS_VIDEO_DECODER_SEND_RPSI, &rpsi);
}
}
send_rpsi_if_reference_frame(ctx, frame);
} else {
/* Drop frames until the first keyframe is successfully received. */
ms_warning("VP8 frame dropped because keyframe has not been received yet.");
frame->discarded = TRUE;
if (ctx->avpf_enabled == TRUE) {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
} else {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
}
send_pli(ctx);
}
} else if (is_frame_marker_present(frame) == TRUE) {
if (is_first_partition_present_in_frame(frame) == TRUE) {
......@@ -428,20 +458,12 @@ static void output_valid_partitions(Vp8RtpFmtUnpackerCtx *ctx, MSQueue *out) {
ms_warning("VP8 frame with some partitions missing/invalid.");
frame->discarded = TRUE;
}
if (ctx->avpf_enabled == TRUE) {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
} else {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
}
send_sli_if_reference_frame(ctx, frame);
} else {
/* Drop the frame for which the first partition is missing. */
ms_warning("VP8 frame without first partition.");
frame->discarded = TRUE;
if (ctx->avpf_enabled == TRUE) {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
} else {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
}
send_sli_if_reference_frame(ctx, frame);
}
} else {
/* The last packet of the frame has not been received.
......@@ -449,11 +471,7 @@ static void output_valid_partitions(Vp8RtpFmtUnpackerCtx *ctx, MSQueue *out) {
ms_warning("VP8 frame without last packet.");
// TODO: Try to get the missing packets at the next iteration of the filter.
frame->discarded = TRUE;
if (ctx->avpf_enabled == TRUE) {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
} else {
ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
}
send_sli_if_reference_frame(ctx, frame);
}
}
}
......
......@@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <mediastreamer2/mscommon.h>
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msqueue.h>
#include <mediastreamer2/msvideo.h>
/**
* This file declares an API useful to pack/unpack a VP8 stream in RTP packets
......@@ -88,6 +89,7 @@ extern "C"{
MSFilter *filter;
MSList *frames_list;
MSQueue output_queue;
MSVideoSize video_size;
uint32_t last_ts;
uint32_t ref_cseq;
bool_t avpf_enabled;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment