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");
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)) {
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 */
}
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;
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;
}
}
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;
+
+ switch_assert(video_data);
+ size &= ~VID_BIT;
+ read_size = size;
+ *(uint32_t *)video_data = size;
- if (status != SWITCH_STATUS_SUCCESS) {
+ 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;
}
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));
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;