[mod_fsv] add video read support to fsv file format

This commit is contained in:
Seven Du 2020-03-30 16:33:39 +08:00 committed by Andrey Volk
parent 6761e8767e
commit 7b46c01e9e
1 changed files with 140 additions and 6 deletions

View File

@ -786,15 +786,24 @@ struct fsv_file_context {
switch_file_t *fd;
char *path;
switch_mutex_t *mutex;
switch_queue_t *video_queue;
switch_codec_t video_codec;
switch_image_t *last_img;
};
typedef struct fsv_file_context fsv_file_context;
typedef struct fsv_file_video_packet_s {
uint8_t *data;
uint32_t len;
} fsv_file_video_packet_t;
static switch_status_t fsv_file_open(switch_file_handle_t *handle, const char *path)
{
fsv_file_context *context;
char *ext;
unsigned int flags = 0;
const char *video_codec = NULL;
if ((ext = strrchr(path, '.')) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Format\n");
@ -827,6 +836,8 @@ static switch_status_t fsv_file_open(switch_file_handle_t *handle, const char *p
return SWITCH_STATUS_GENERR;
}
switch_queue_create(&context->video_queue, 500, handle->memory_pool);
context->path = switch_core_strdup(handle->memory_pool, path);
if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) {
@ -855,7 +866,9 @@ static switch_status_t fsv_file_open(switch_file_handle_t *handle, const char *p
h.version = VERSION;
h.created = switch_micro_time_now();
switch_set_string(h.video_codec_name, "H264"); /* FIXME: hard coded */
video_codec = switch_event_get_header(handle->params, "video_codec_name");
if (zstr(video_codec)) video_codec = "VP8";
switch_set_string(h.video_codec_name, video_codec);
h.audio_rate = handle->samplerate;
h.audio_ptime = 20; /* FIXME: hard coded */
@ -879,6 +892,22 @@ static switch_status_t fsv_file_open(switch_file_handle_t *handle, const char *p
}
handle->samplerate = h.audio_rate;
video_codec = switch_core_strdup(handle->memory_pool, h.video_codec_name);
}
if (video_codec) {
if (switch_core_codec_init(&context->video_codec,
video_codec,
NULL,
NULL,
90000,
0,
0, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL, handle->memory_pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Video Codec Activation Failed\n");
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Video Codec [%s] ready\n", video_codec);
}
}
return SWITCH_STATUS_SUCCESS;
@ -908,6 +937,20 @@ static switch_status_t fsv_file_close(switch_file_handle_t *handle)
context->fd = NULL;
}
if (switch_test_flag(&context->video_codec, SWITCH_CODEC_FLAG_READY)) {
switch_core_codec_destroy(&context->video_codec);
}
if (context->video_queue) {
void *pop;
while (switch_queue_trypop(context->video_queue, &pop) == SWITCH_STATUS_SUCCESS) {
free(pop);
}
}
switch_img_free(&context->last_img);
return SWITCH_STATUS_SUCCESS;
}
@ -934,15 +977,30 @@ again:
}
if (size & VID_BIT) { /* video */
*len = size & ~VID_BIT;
/* TODO: read video data */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "discarding video data %d\n", (int)*len);
status = switch_file_read(context->fd, data, len);
uint8_t *video_data = malloc(sizeof(size) + size);
switch_size_t read_size;
if (status != SWITCH_STATUS_SUCCESS) {
switch_assert(video_data);
size &= ~VID_BIT;
read_size = size;
*(uint32_t *)video_data = size;
status = switch_file_read(context->fd, video_data + sizeof(size), &read_size);
if (status != SWITCH_STATUS_SUCCESS || read_size != size) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"read error status=%d size=%u read_size=%" SWITCH_SIZE_T_FMT "\n",
status, size, read_size);
goto end;
}
switch_mutex_lock(context->mutex);
if (switch_queue_trypush(context->video_queue, video_data) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "queue overflow!!\n");
free(video_data);
}
switch_mutex_unlock(context->mutex);
handle->pos += *len + bytes;
goto again;
}
@ -963,6 +1021,81 @@ end:
return status;
}
static switch_status_t fsv_file_read_video(switch_file_handle_t *handle, switch_frame_t *frame, switch_video_read_flag_t flags)
{
fsv_file_context *context = handle->private_info;
switch_image_t *dup = NULL;
switch_status_t status = SWITCH_STATUS_SUCCESS;
void *video_packet = NULL;
switch_time_t start = switch_time_now();
switch_status_t decode_status = SWITCH_STATUS_MORE_DATA;
int new_img = 0;
if ((flags & SVR_CHECK)) {
switch_goto_status(SWITCH_STATUS_BREAK, end);
}
while (!new_img) {
while (decode_status == SWITCH_STATUS_MORE_DATA || decode_status == SWITCH_STATUS_SUCCESS) {
switch_frame_t rtp_frame = { 0 };
uint32_t size;
switch_rtp_hdr_t *rtp;
switch_mutex_lock(context->mutex);
status = switch_queue_trypop(context->video_queue, &video_packet);
switch_mutex_unlock(context->mutex);
if (status != SWITCH_STATUS_SUCCESS || !video_packet) break;
size = *(uint32_t *)video_packet;
rtp = (switch_rtp_hdr_t *)((uint8_t *)video_packet + sizeof(uint32_t));
rtp_frame.packet = rtp;
rtp_frame.packetlen = size;
rtp_frame.data = (uint8_t *)rtp_frame.packet + 12;
rtp_frame.datalen = size - 12;
rtp_frame.m = rtp->m;
rtp_frame.timestamp = ntohl(rtp->ts);
decode_status = switch_core_codec_decode_video(&context->video_codec, &rtp_frame);
rtp_frame.packet = NULL;
rtp_frame.data = NULL;
rtp_frame.datalen = 0;
rtp_frame.packetlen = 0;
free(video_packet);
if (rtp_frame.img) {
switch_img_copy(rtp_frame.img, &context->last_img);
new_img = 1;
break;
} else if (rtp_frame.m) {
break;
}
}
if (!(flags & SVR_BLOCK)) {
break;
}
if (switch_time_now() - start < 33000) {
switch_yield(10000);
} else {
break;
}
}
if (context->last_img) {
switch_img_copy(context->last_img, &dup);
frame->img = dup;
status = SWITCH_STATUS_SUCCESS;
} else {
status = SWITCH_STATUS_BREAK;
}
end:
return status;
}
static switch_status_t fsv_file_write(switch_file_handle_t *handle, void *data, size_t *len)
{
uint32_t datalen = (uint32_t)(*len * sizeof(int16_t));
@ -1071,6 +1204,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_fsv_load)
file_interface->file_close = fsv_file_close;
file_interface->file_truncate = fsv_file_truncate;
file_interface->file_read = fsv_file_read;
file_interface->file_read_video = fsv_file_read_video;
file_interface->file_write = fsv_file_write;
#if 0
file_interface->file_write_video = fsv_file_write_video;