Merge pull request #770 in FS/freeswitch from FS-8750-1 to master
* commit 'bdeacb1d29d78626474bf53cf8969bf3ea20c751': FS-8751 [Conference Play Video Total Time and Current Time] FS-8748 FS-8751 check current play_status FS-8748 track pdf total pages and current page FS-8754 add ability to read high quality PDF FS-8750 implement file_seek for video files
This commit is contained in:
commit
fdedaadd23
|
@ -394,6 +394,10 @@ struct switch_file_handle {
|
|||
char *modname;
|
||||
switch_mm_t mm;
|
||||
switch_mutex_t *flag_mutex;
|
||||
/*! total video duration, or total page in pdf*/
|
||||
int64_t duration;
|
||||
/*! current video position, or current page in pdf */
|
||||
int64_t vpos;
|
||||
};
|
||||
|
||||
/*! \brief Abstract interface to an asr module */
|
||||
|
|
|
@ -1264,6 +1264,7 @@ struct av_file_context {
|
|||
switch_image_t *last_img;
|
||||
int read_fps;
|
||||
switch_time_t last_vid_push;
|
||||
int64_t seek_ts;
|
||||
};
|
||||
|
||||
typedef struct av_file_context av_file_context_t;
|
||||
|
@ -1296,6 +1297,9 @@ static switch_status_t open_input_file(av_file_context_t *context, switch_file_h
|
|||
switch_goto_status(SWITCH_STATUS_FALSE, err);
|
||||
}
|
||||
|
||||
handle->seekable = context->fc->iformat->read_seek2 ? 1 : (context->fc->iformat->read_seek ? 1 : 0);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "file %s is %sseekable\n", filename, handle->seekable ? "" : "not ");
|
||||
|
||||
/** Get information on the input file (number of streams etc.). */
|
||||
if ((error = avformat_find_stream_info(context->fc, NULL)) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open find stream info (error '%s')\n", get_error_text(error));
|
||||
|
@ -1312,6 +1316,7 @@ static switch_status_t open_input_file(av_file_context_t *context, switch_file_h
|
|||
context->video_st.st = context->fc->streams[i];
|
||||
if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
|
||||
context->has_video = 1;
|
||||
handle->duration = av_rescale_q(context->video_st.st->duration, context->video_st.st->time_base, AV_TIME_BASE_Q);
|
||||
}
|
||||
handle->mm.source_fps = ceil(av_q2d(context->video_st.st->avg_frame_rate));
|
||||
context->read_fps = (int)handle->mm.source_fps;
|
||||
|
@ -1365,14 +1370,18 @@ static switch_status_t open_input_file(av_file_context_t *context, switch_file_h
|
|||
av_opt_set_int(resample_ctx, "in_channel_count", c->channels, 0);
|
||||
av_opt_set_int(resample_ctx, "in_sample_rate", c->sample_rate, 0);
|
||||
av_opt_set_int(resample_ctx, "in_sample_fmt", c->sample_fmt, 0);
|
||||
av_opt_set_int(resample_ctx, "in_channel_layout", c->channel_layout, 0);
|
||||
av_opt_set_int(resample_ctx, "in_channel_layout",
|
||||
(c->channel_layout == 0 && c->channels == 2) ? AV_CH_LAYOUT_STEREO : c->channel_layout, 0);
|
||||
av_opt_set_int(resample_ctx, "out_channel_count", handle->channels, 0);
|
||||
av_opt_set_int(resample_ctx, "out_sample_rate", handle->samplerate,0);
|
||||
av_opt_set_int(resample_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
|
||||
av_opt_set_int(resample_ctx, "out_channel_layout", handle->channels == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO, 0);
|
||||
|
||||
if ((ret = avresample_open(resample_ctx)) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the resampling context\n");
|
||||
char errbuf[1024];
|
||||
av_strerror(ret, errbuf, 1024);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the resampling context, ret=%d: %s\n", ret, errbuf);
|
||||
av_free(resample_ctx);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, err);
|
||||
}
|
||||
|
@ -1411,6 +1420,28 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
|
|||
while (context->file_read_thread_running && !context->closed) {
|
||||
int vid_frames = 0;
|
||||
|
||||
if (context->seek_ts >= 0) {
|
||||
int ret = 0;
|
||||
int stream_id = -1;
|
||||
|
||||
switch_mutex_lock(context->mutex);
|
||||
switch_buffer_zero(context->audio_buffer);
|
||||
switch_mutex_unlock(context->mutex);
|
||||
|
||||
if (context->eh.video_queue) {
|
||||
flush_video_queue(context->eh.video_queue, 0);
|
||||
}
|
||||
|
||||
// if (context->has_audio) stream_id = context->audio_st.st->index;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "seeking to %" SWITCH_INT64_T_FMT "\n", context->seek_ts);
|
||||
ret = avformat_seek_file(context->fc, stream_id, 0, context->seek_ts, INT64_MAX, 0);
|
||||
context->seek_ts = -1;
|
||||
context->video_st.next_pts = 0;
|
||||
context->video_start_time = 0;
|
||||
|
||||
avcodec_flush_buffers(context->video_st.st->codec);
|
||||
}
|
||||
|
||||
if (context->has_video) {
|
||||
vid_frames = switch_queue_size(context->eh.video_queue);
|
||||
}
|
||||
|
@ -1514,7 +1545,7 @@ again:
|
|||
|
||||
img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, vframe->width, vframe->height, 1);
|
||||
if (img) {
|
||||
uint64_t *pts = malloc(sizeof(uint64_t));
|
||||
int64_t *pts = malloc(sizeof(int64_t));
|
||||
|
||||
if (pts) {
|
||||
#ifdef ALT_WAY
|
||||
|
@ -1643,7 +1674,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
|
|||
memset(context, 0, sizeof(av_file_context_t));
|
||||
handle->private_info = context;
|
||||
context->pool = handle->memory_pool;
|
||||
|
||||
context->seek_ts = -1;
|
||||
context->offset = DFT_RECORD_OFFSET;
|
||||
if (handle->params && (tmp = switch_event_get_header(handle->params, "av_video_offset"))) {
|
||||
context->offset = atoi(tmp);
|
||||
|
@ -1989,7 +2020,15 @@ static switch_status_t av_file_close(switch_file_handle_t *handle)
|
|||
|
||||
static switch_status_t av_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence)
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "seek not implemented\n");
|
||||
av_file_context_t *context = (av_file_context_t *)handle->private_info;
|
||||
|
||||
if (whence == SEEK_SET) {
|
||||
handle->pos = handle->offset_pos = samples;
|
||||
}
|
||||
|
||||
context->seek_ts = samples / handle->native_rate * AV_TIME_BASE;
|
||||
*cur_sample = context->seek_ts;
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -2151,6 +2190,7 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
|
|||
|
||||
pts = av_rescale_q(*((uint64_t *)img->user_priv), st->time_base, AV_TIME_BASE_Q);
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "pkt_pts: %lld pts: %lld queue size: %u\n", *((uint64_t *)img->user_priv), pts, switch_queue_size(context->eh.video_queue));
|
||||
handle->vpos = pts;
|
||||
|
||||
if (!context->video_start_time) {
|
||||
context->video_start_time = now - pts;
|
||||
|
|
|
@ -55,6 +55,7 @@ api_command_t conference_api_sub_commands[] = {
|
|||
{"auto-3d-position", (void_fn_t) & conference_api_sub_auto_position, CONF_API_SUB_ARGS_SPLIT, "auto-3d-position", "[on|off]"},
|
||||
{"play", (void_fn_t) & conference_api_sub_play, CONF_API_SUB_ARGS_SPLIT, "play", "<file_path> [async|<member_id> [nomux]]"},
|
||||
{"pause_play", (void_fn_t) & conference_api_sub_pause_play, CONF_API_SUB_ARGS_SPLIT, "pause", "[<member_id>]"},
|
||||
{"play_status", (void_fn_t) & conference_api_sub_play_status, CONF_API_SUB_ARGS_SPLIT, "play_status", "[<member_id>]"},
|
||||
{"file_seek", (void_fn_t) & conference_api_sub_file_seek, CONF_API_SUB_ARGS_SPLIT, "file_seek", "[+-]<val> [<member_id>]"},
|
||||
{"say", (void_fn_t) & conference_api_sub_say, CONF_API_SUB_ARGS_AS_ONE, "say", "<text>"},
|
||||
{"saymember", (void_fn_t) & conference_api_sub_saymember, CONF_API_SUB_ARGS_AS_ONE, "saymember", "<member_id> <text>"},
|
||||
|
@ -135,6 +136,34 @@ switch_status_t conference_api_sub_pause_play(conference_obj_t *conference, swit
|
|||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
switch_status_t conference_api_sub_play_status(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
|
||||
{
|
||||
if (argc == 2) {
|
||||
switch_mutex_lock(conference->mutex);
|
||||
conference_fnode_check_status(conference->fnode, stream);
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
uint32_t id = atoi(argv[2]);
|
||||
conference_member_t *member;
|
||||
|
||||
if ((member = conference_member_get(conference, id))) {
|
||||
switch_mutex_lock(member->fnode_mutex);
|
||||
conference_fnode_check_status(member->fnode, stream);
|
||||
switch_mutex_unlock(member->fnode_mutex);
|
||||
switch_thread_rwlock_unlock(member->rwlock);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
stream->write_function(stream, "Member: %u not found.\n", id);
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
/* _In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream */
|
||||
switch_status_t conference_api_main_real(const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream)
|
||||
{
|
||||
|
|
|
@ -1264,6 +1264,15 @@ void conference_fnode_toggle_pause(conference_file_node_t *fnode, switch_stream_
|
|||
}
|
||||
}
|
||||
|
||||
void conference_fnode_check_status(conference_file_node_t *fnode, switch_stream_handle_t *stream)
|
||||
{
|
||||
if (fnode) {
|
||||
stream->write_function(stream, "+OK %"SWITCH_INT64_T_FMT "/%" SWITCH_INT64_T_FMT " %s\n",
|
||||
fnode->fh.vpos, fnode->fh.duration, fnode->fh.file_path);
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Nothing is playing\n");
|
||||
}
|
||||
}
|
||||
|
||||
void conference_fnode_seek(conference_file_node_t *fnode, switch_stream_handle_t *stream, char *arg)
|
||||
{
|
||||
|
|
|
@ -967,6 +967,7 @@ int conference_member_noise_gate_check(conference_member_t *member);
|
|||
void conference_member_check_channels(switch_frame_t *frame, conference_member_t *member, switch_bool_t in);
|
||||
|
||||
void conference_fnode_toggle_pause(conference_file_node_t *fnode, switch_stream_handle_t *stream);
|
||||
void conference_fnode_check_status(conference_file_node_t *fnode, switch_stream_handle_t *stream);
|
||||
|
||||
// static conference_relationship_t *conference_member_get_relationship(conference_member_t *member, conference_member_t *other_member);
|
||||
// static void conference_list(conference_obj_t *conference, switch_stream_handle_t *stream, char *delim);
|
||||
|
@ -1062,6 +1063,7 @@ switch_status_t conference_api_sub_position(conference_member_t *member, switch_
|
|||
switch_status_t conference_api_sub_conference_video_vmute_snap(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_dtmf(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_pause_play(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_play_status(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_play(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_say(conference_obj_t *conference, switch_stream_handle_t *stream, const char *text);
|
||||
switch_status_t conference_api_sub_dial(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
|
|
|
@ -123,6 +123,33 @@ static switch_status_t imagick_file_open(switch_file_handle_t *handle, const cha
|
|||
context->image_info = AcquireImageInfo();
|
||||
switch_set_string(context->image_info->filename, path);
|
||||
|
||||
if (handle->params) {
|
||||
const char *max = switch_event_get_header(handle->params, "img_ms");
|
||||
const char *autoplay = switch_event_get_header(handle->params, "autoplay");
|
||||
const char *density = switch_event_get_header(handle->params, "density");
|
||||
const char *quality = switch_event_get_header(handle->params, "quality");
|
||||
int tmp;
|
||||
|
||||
if (max) {
|
||||
tmp = atol(max);
|
||||
context->max = tmp;
|
||||
}
|
||||
|
||||
if (autoplay) {
|
||||
context->autoplay = atoi(autoplay);
|
||||
}
|
||||
|
||||
if (density) {
|
||||
context->image_info->density = strdup(density);
|
||||
}
|
||||
|
||||
if (quality) {
|
||||
tmp = atoi(quality);
|
||||
|
||||
if (tmp > 0) context->image_info->quality = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
context->images = ReadImages(context->image_info, context->exception);
|
||||
if (context->exception->severity != UndefinedException) {
|
||||
CatchException(context->exception);
|
||||
|
@ -134,21 +161,7 @@ static switch_status_t imagick_file_open(switch_file_handle_t *handle, const cha
|
|||
}
|
||||
|
||||
context->pagecount = GetImageListLength(context->images);
|
||||
|
||||
if (handle->params) {
|
||||
const char *max = switch_event_get_header(handle->params, "img_ms");
|
||||
const char *autoplay = switch_event_get_header(handle->params, "autoplay");
|
||||
int tmp;
|
||||
|
||||
if (max) {
|
||||
tmp = atol(max);
|
||||
context->max = tmp;
|
||||
}
|
||||
|
||||
if (autoplay) {
|
||||
context->autoplay = atoi(autoplay);
|
||||
}
|
||||
}
|
||||
handle->duration = context->pagecount;
|
||||
|
||||
if (context->max) {
|
||||
context->samples = (handle->samplerate / 1000) * context->max;
|
||||
|
@ -347,6 +360,7 @@ static switch_status_t imagick_file_seek(switch_file_handle_t *handle, unsigned
|
|||
context->pagenumber = page;
|
||||
context->same_page = 0;
|
||||
*cur_sample = page;
|
||||
handle->vpos = page;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
Loading…
Reference in New Issue