forked from Mirrors/freeswitch
[mod_fsv] add video read support to fsv file format
This commit is contained in:
parent
6761e8767e
commit
7b46c01e9e
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue