]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-8750 implement file_seek for video files
authorSeven Du <dujinfang@gmail.com>
Sat, 13 Feb 2016 03:18:15 +0000 (11:18 +0800)
committerSeven Du <dujinfang@gmail.com>
Thu, 17 Mar 2016 01:34:43 +0000 (09:34 +0800)
src/mod/applications/mod_av/avformat.c

index 4d08f70644df39fa5cd81987e6271d8cea4e6636..1b5562a135875d5e3d249469cc54451cd579b4e1 100644 (file)
@@ -366,7 +366,7 @@ static switch_status_t add_stream(MediaStream *mst, AVFormatContext *fc, AVCodec
                        c->me_method=ME_HEX;    // me_method=hex
                        c->me_range = 16;   // me_range=16
                        c->max_b_frames = 3;    // bf=3
-                       
+
                        switch (mm->vprofile) {
                        case SWITCH_VIDEO_PROFILE_BASELINE:
                                av_opt_set(c->priv_data, "profile", "baseline", 0);
@@ -677,21 +677,21 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
                        eh->video_st->frame->pts += delta;
                } else {
                        switch_core_timer_sync(eh->timer);
-               
+
                        if (eh->video_st->frame->pts == eh->timer->samplecount) {
                                // never use the same pts, or the encoder coughs
                                eh->video_st->frame->pts++;
                        } else {
                                uint64_t delta_tmp = eh->timer->samplecount - last_ts;
-                               
+
                                if (delta_tmp > 10) {
                                        delta = delta_tmp;
                                }
-                               
+
                                eh->video_st->frame->pts = eh->timer->samplecount;
                        }
                }
-               
+
                last_ts = eh->video_st->frame->pts;
 
                //eh->video_st->frame->pts = switch_time_now() / 1000 - eh->video_st->next_pts;
@@ -1245,6 +1245,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;
@@ -1277,6 +1278,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));
@@ -1346,14 +1350,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);
                                }
@@ -1392,11 +1400,33 @@ 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);
                }
 
-               if (switch_buffer_inuse(context->audio_buffer) > AUDIO_BUF_SEC * context->audio_st.sample_rate * context->audio_st.channels * 2 && 
+               if (switch_buffer_inuse(context->audio_buffer) > AUDIO_BUF_SEC * context->audio_st.sample_rate * context->audio_st.channels * 2 &&
                        (!context->has_video || vid_frames > 5)) {
                        switch_yield(context->has_video ? 1000 : 10000);
                        continue;
@@ -1495,7 +1525,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
@@ -1624,7 +1654,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);
@@ -1699,7 +1729,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
                const AVCodecDescriptor *desc;
 
                if ((handle->stream_name && (!strcasecmp(handle->stream_name, "rtmp") || !strcasecmp(handle->stream_name, "youtube")))) {
-                       
+
                        if (fmt->video_codec != AV_CODEC_ID_H264 ) {
                                fmt->video_codec = AV_CODEC_ID_H264; // force H264
                        }
@@ -1970,7 +2000,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;
 }