Merge commit 'b35e5d985dd12acf9a0aaa52334134edcf35d68e'
* commit 'b35e5d985dd12acf9a0aaa52334134edcf35d68e': doc: improve documentation for the asyncts filter first_pts option asyncts: fix the asyncts behavior when using the first_pts option Conflicts: libavfilter/af_asyncts.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
		
						commit
						b6e7041f90
					
				| @ -782,11 +782,12 @@ Maximum compensation in samples per second. Relevant only with compensate=1. | ||||
| Default value 500. | ||||
| 
 | ||||
| @item first_pts | ||||
| Assume the first pts should be this value. | ||||
| Assume the first pts should be this value. The time base is 1 / sample rate. | ||||
| This allows for padding/trimming at the start of stream. By default, no | ||||
| assumption is made about the first frame's expected pts, so no padding or | ||||
| trimming is done. For example, this could be set to 0 to pad the beginning with | ||||
| silence if an audio stream starts after the video stream. | ||||
| silence if an audio stream starts after the video stream or to trim any samples | ||||
| with a negative pts due to encoder delay. | ||||
| 
 | ||||
| @end table | ||||
| 
 | ||||
|  | ||||
| @ -33,6 +33,8 @@ typedef struct ASyncContext { | ||||
|     AVAudioResampleContext *avr; | ||||
|     int64_t pts;            ///< timestamp in samples of the first sample in fifo
 | ||||
|     int min_delta;          ///< pad/trim min threshold in samples
 | ||||
|     int first_frame;        ///< 1 until filter_frame() has processed at least 1 frame with a pts != AV_NOPTS_VALUE
 | ||||
|     int64_t first_pts;      ///< user-specified first expected pts, in samples
 | ||||
| 
 | ||||
|     /* options */ | ||||
|     int resample; | ||||
| @ -51,7 +53,7 @@ static const AVOption asyncts_options[] = { | ||||
|     { "min_delta",  "Minimum difference between timestamps and audio data " | ||||
|                     "(in seconds) to trigger padding/trimmin the data.",        OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { .dbl = 0.1 }, 0, INT_MAX, A|F }, | ||||
|     { "max_comp",   "Maximum compensation in samples per second.",              OFFSET(max_comp),      AV_OPT_TYPE_INT,   { .i64 = 500 }, 0, INT_MAX, A|F }, | ||||
|     { "first_pts",  "Assume the first pts should be this value.",               OFFSET(pts),           AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, A|F }, | ||||
|     { "first_pts",  "Assume the first pts should be this value.",               OFFSET(first_pts),     AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, A|F }, | ||||
|     { NULL }, | ||||
| }; | ||||
| 
 | ||||
| @ -69,6 +71,9 @@ static int init(AVFilterContext *ctx, const char *args) | ||||
|         return ret; | ||||
|     av_opt_free(s); | ||||
| 
 | ||||
|     s->pts         = AV_NOPTS_VALUE; | ||||
|     s->first_frame = 1; | ||||
| 
 | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| @ -116,6 +121,20 @@ static int64_t get_delay(ASyncContext *s) | ||||
|     return avresample_available(s->avr) + avresample_get_delay(s->avr); | ||||
| } | ||||
| 
 | ||||
| static void handle_trimming(AVFilterContext *ctx) | ||||
| { | ||||
|     ASyncContext *s = ctx->priv; | ||||
| 
 | ||||
|     if (s->pts < s->first_pts) { | ||||
|         int delta = FFMIN(s->first_pts - s->pts, avresample_available(s->avr)); | ||||
|         av_log(ctx, AV_LOG_VERBOSE, "Trimming %d samples from start\n", | ||||
|                delta); | ||||
|         avresample_read(s->avr, NULL, delta); | ||||
|         s->pts += delta; | ||||
|     } else if (s->first_frame) | ||||
|         s->pts = s->first_pts; | ||||
| } | ||||
| 
 | ||||
| static int request_frame(AVFilterLink *link) | ||||
| { | ||||
|     AVFilterContext *ctx = link->src; | ||||
| @ -128,7 +147,11 @@ static int request_frame(AVFilterLink *link) | ||||
|         ret = ff_request_frame(ctx->inputs[0]); | ||||
| 
 | ||||
|     /* flush the fifo */ | ||||
|     if (ret == AVERROR_EOF && (nb_samples = get_delay(s))) { | ||||
|     if (ret == AVERROR_EOF) { | ||||
|         if (s->first_pts != AV_NOPTS_VALUE) | ||||
|             handle_trimming(ctx); | ||||
| 
 | ||||
|         if (nb_samples = get_delay(s)) { | ||||
|         AVFilterBufferRef *buf = ff_get_audio_buffer(link, AV_PERM_WRITE, | ||||
|                                                      nb_samples); | ||||
|         if (!buf) | ||||
| @ -143,6 +166,7 @@ static int request_frame(AVFilterLink *link) | ||||
|         buf->pts = s->pts; | ||||
|         return ff_filter_frame(link, buf); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| @ -179,12 +203,18 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | ||||
|         return write_to_fifo(s, buf); | ||||
|     } | ||||
| 
 | ||||
|     if (s->first_pts != AV_NOPTS_VALUE) { | ||||
|         handle_trimming(ctx); | ||||
|         if (!avresample_available(s->avr)) | ||||
|             return write_to_fifo(s, buf); | ||||
|     } | ||||
| 
 | ||||
|     /* when we have two timestamps, compute how many samples would we have
 | ||||
|      * to add/remove to get proper sync between data and timestamps */ | ||||
|     delta    = pts - s->pts - get_delay(s); | ||||
|     out_size = avresample_available(s->avr); | ||||
| 
 | ||||
|     if (labs(delta) > s->min_delta) { | ||||
|     if (labs(delta) > s->min_delta || (s->first_frame && delta)) { | ||||
|         av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta); | ||||
|         out_size = av_clipl_int32((int64_t)out_size + delta); | ||||
|     } else { | ||||
| @ -204,18 +234,33 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | ||||
|             goto fail; | ||||
|         } | ||||
| 
 | ||||
|         if (s->first_frame && delta > 0) { | ||||
|             int ch; | ||||
| 
 | ||||
|             av_samples_set_silence(buf_out->extended_data, 0, delta, | ||||
|                                    nb_channels, buf->format); | ||||
| 
 | ||||
|             for (ch = 0; ch < nb_channels; ch++) | ||||
|                 buf_out->extended_data[ch] += delta; | ||||
| 
 | ||||
|             avresample_read(s->avr, buf_out->extended_data, out_size); | ||||
| 
 | ||||
|             for (ch = 0; ch < nb_channels; ch++) | ||||
|                 buf_out->extended_data[ch] -= delta; | ||||
|         } else { | ||||
|             avresample_read(s->avr, buf_out->extended_data, out_size); | ||||
|         buf_out->pts = s->pts; | ||||
| 
 | ||||
|             if (delta > 0) { | ||||
|                 av_samples_set_silence(buf_out->extended_data, out_size - delta, | ||||
|                                        delta, nb_channels, buf->format); | ||||
|             } | ||||
|         } | ||||
|         buf_out->pts = s->pts; | ||||
|         ret = ff_filter_frame(outlink, buf_out); | ||||
|         if (ret < 0) | ||||
|             goto fail; | ||||
|         s->got_output = 1; | ||||
|     } else { | ||||
|     } else if (avresample_available(s->avr)) { | ||||
|         av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping " | ||||
|                "whole buffer.\n"); | ||||
|     } | ||||
| @ -227,6 +272,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | ||||
|     ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data, | ||||
|                              buf->linesize[0], buf->audio->nb_samples); | ||||
| 
 | ||||
|     s->first_frame = 0; | ||||
| fail: | ||||
|     avfilter_unref_buffer(buf); | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user