You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	lavfi: add amovie source - audio movie source
This commit is contained in:
		| @@ -46,6 +46,7 @@ easier to use. The changes are: | ||||
| - LOAS demuxer | ||||
| - ashowinfo filter added | ||||
| - Windows Media Image decoder | ||||
| - amovie source added | ||||
|  | ||||
|  | ||||
| version 0.8: | ||||
|   | ||||
							
								
								
									
										1
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -1505,6 +1505,7 @@ udp_protocol_deps="network" | ||||
| # filters | ||||
| abuffer_filter_deps="strtok_r" | ||||
| aformat_filter_deps="strtok_r" | ||||
| amovie_filter_deps="avcodec avformat" | ||||
| blackframe_filter_deps="gpl" | ||||
| boxblur_filter_deps="gpl" | ||||
| cropdetect_filter_deps="gpl" | ||||
|   | ||||
| @@ -239,6 +239,38 @@ equivalent to: | ||||
| abuffer=44100:1:3:1 | ||||
| @end example | ||||
|  | ||||
| @section amovie | ||||
|  | ||||
| Read an audio stream from a movie container. | ||||
|  | ||||
| It accepts the syntax: @var{movie_name}[:@var{options}] where | ||||
| @var{movie_name} is the name of the resource to read (not necessarily | ||||
| a file but also a device or a stream accessed through some protocol), | ||||
| and @var{options} is an optional sequence of @var{key}=@var{value} | ||||
| pairs, separated by ":". | ||||
|  | ||||
| The description of the accepted options follows. | ||||
|  | ||||
| @table @option | ||||
|  | ||||
| @item format_name, f | ||||
| Specify the format assumed for the movie to read, and can be either | ||||
| the name of a container or an input device. If not specified the | ||||
| format is guessed from @var{movie_name} or by probing. | ||||
|  | ||||
| @item seek_point, sp | ||||
| Specify the seek point in seconds, the frames will be output | ||||
| starting from this seek point, the parameter is evaluated with | ||||
| @code{av_strtod} so the numerical value may be suffixed by an IS | ||||
| postfix. Default value is "0". | ||||
|  | ||||
| @item stream_index, si | ||||
| Specify the index of the audio stream to read. If the value is -1, | ||||
| the best suited audio stream will be automatically selected. Default | ||||
| value is "-1". | ||||
|  | ||||
| @end table | ||||
|  | ||||
| @section anullsrc | ||||
|  | ||||
| Null audio source, never return audio frames. It is mainly useful as a | ||||
|   | ||||
| @@ -2,6 +2,7 @@ include $(SUBDIR)../config.mak | ||||
|  | ||||
| NAME = avfilter | ||||
| FFLIBS = avutil | ||||
| FFLIBS-$(CONFIG_AMOVIE_FILTER) += avformat avcodec | ||||
| FFLIBS-$(CONFIG_ARESAMPLE_FILTER) += avcodec | ||||
| FFLIBS-$(CONFIG_MOVIE_FILTER) += avformat avcodec | ||||
| FFLIBS-$(CONFIG_SCALE_FILTER) += swscale | ||||
| @@ -25,6 +26,7 @@ OBJS-$(CONFIG_ARESAMPLE_FILTER)              += af_aresample.o | ||||
| OBJS-$(CONFIG_ASHOWINFO_FILTER)              += af_ashowinfo.o | ||||
|  | ||||
| OBJS-$(CONFIG_ABUFFER_FILTER)                += asrc_abuffer.o | ||||
| OBJS-$(CONFIG_AMOVIE_FILTER)                 += src_movie.o | ||||
| OBJS-$(CONFIG_ANULLSRC_FILTER)               += asrc_anullsrc.o | ||||
|  | ||||
| OBJS-$(CONFIG_ABUFFERSINK_FILTER)            += asink_abuffer.o | ||||
|   | ||||
| @@ -40,6 +40,7 @@ void avfilter_register_all(void) | ||||
|     REGISTER_FILTER (ASHOWINFO,   ashowinfo,   af); | ||||
|  | ||||
|     REGISTER_FILTER (ABUFFER,     abuffer,     asrc); | ||||
|     REGISTER_FILTER (AMOVIE,      amovie,      asrc); | ||||
|     REGISTER_FILTER (ANULLSRC,    anullsrc,    asrc); | ||||
|  | ||||
|     REGISTER_FILTER (ABUFFERSINK, abuffersink, asink); | ||||
|   | ||||
| @@ -29,8 +29,8 @@ | ||||
| #include "libavutil/rational.h" | ||||
|  | ||||
| #define LIBAVFILTER_VERSION_MAJOR  2 | ||||
| #define LIBAVFILTER_VERSION_MINOR 34 | ||||
| #define LIBAVFILTER_VERSION_MICRO  2 | ||||
| #define LIBAVFILTER_VERSION_MINOR 35 | ||||
| #define LIBAVFILTER_VERSION_MICRO  0 | ||||
|  | ||||
| #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ | ||||
|                                                LIBAVFILTER_VERSION_MINOR, \ | ||||
|   | ||||
| @@ -55,6 +55,13 @@ typedef struct { | ||||
|     /* video-only fields */ | ||||
|     int w, h; | ||||
|     AVFilterBufferRef *picref; | ||||
|  | ||||
|     /* audio-only fields */ | ||||
|     void *samples_buf; | ||||
|     int samples_buf_size; | ||||
|     int bps;            ///< bytes per sample | ||||
|     AVPacket pkt, pkt0; | ||||
|     AVFilterBufferRef *samplesref; | ||||
| } MovieContext; | ||||
|  | ||||
| #define OFFSET(x) offsetof(MovieContext, x) | ||||
| @@ -185,8 +192,13 @@ static av_cold void movie_common_uninit(AVFilterContext *ctx) | ||||
|  | ||||
|     avfilter_unref_buffer(movie->picref); | ||||
|     av_freep(&movie->frame); | ||||
|  | ||||
|     avfilter_unref_buffer(movie->samplesref); | ||||
|     av_freep(&movie->samples_buf); | ||||
| } | ||||
|  | ||||
| #if CONFIG_MOVIE_FILTER | ||||
|  | ||||
| static av_cold int movie_init(AVFilterContext *ctx, const char *args, void *opaque) | ||||
| { | ||||
|     MovieContext *movie = ctx->priv; | ||||
| @@ -317,3 +329,148 @@ AVFilter avfilter_vsrc_movie = { | ||||
|                                     .config_props    = movie_config_output_props, }, | ||||
|                                   { .name = NULL}}, | ||||
| }; | ||||
|  | ||||
| #endif  /* CONFIG_MOVIE_FILTER */ | ||||
|  | ||||
| #if CONFIG_AMOVIE_FILTER | ||||
|  | ||||
| static av_cold int amovie_init(AVFilterContext *ctx, const char *args, void *opaque) | ||||
| { | ||||
|     MovieContext *movie = ctx->priv; | ||||
|     int ret; | ||||
|  | ||||
|     if ((ret = movie_common_init(ctx, args, opaque, AVMEDIA_TYPE_AUDIO)) < 0) | ||||
|         return ret; | ||||
|  | ||||
|     movie->bps = av_get_bytes_per_sample(movie->codec_ctx->sample_fmt); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int amovie_query_formats(AVFilterContext *ctx) | ||||
| { | ||||
|     MovieContext *movie = ctx->priv; | ||||
|     AVCodecContext *c = movie->codec_ctx; | ||||
|  | ||||
|     enum AVSampleFormat sample_fmts[] = { c->sample_fmt, -1 }; | ||||
|     int packing_fmts[] = { AVFILTER_PACKED, -1 }; | ||||
|     int64_t chlayouts[] = { c->channel_layout, -1 }; | ||||
|  | ||||
|     avfilter_set_common_sample_formats (ctx, avfilter_make_format_list(sample_fmts)); | ||||
|     avfilter_set_common_packing_formats(ctx, avfilter_make_format_list(packing_fmts)); | ||||
|     avfilter_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts)); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int amovie_config_output_props(AVFilterLink *outlink) | ||||
| { | ||||
|     MovieContext *movie = outlink->src->priv; | ||||
|     AVCodecContext *c = movie->codec_ctx; | ||||
|  | ||||
|     outlink->sample_rate = c->sample_rate; | ||||
|     outlink->time_base = movie->format_ctx->streams[movie->stream_index]->time_base; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int amovie_get_samples(AVFilterLink *outlink) | ||||
| { | ||||
|     MovieContext *movie = outlink->src->priv; | ||||
|     AVPacket pkt; | ||||
|     int ret, samples_size, decoded_data_size; | ||||
|  | ||||
|     if (!movie->pkt.size && movie->is_done == 1) | ||||
|         return AVERROR_EOF; | ||||
|  | ||||
|     /* check for another frame, in case the previous one was completely consumed */ | ||||
|     if (!movie->pkt.size) { | ||||
|         while ((ret = av_read_frame(movie->format_ctx, &pkt)) >= 0) { | ||||
|             // Is this a packet from the selected stream? | ||||
|             if (pkt.stream_index != movie->stream_index) { | ||||
|                 av_free_packet(&pkt); | ||||
|                 continue; | ||||
|             } else { | ||||
|                 movie->pkt0 = movie->pkt = pkt; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (ret == AVERROR_EOF) { | ||||
|             movie->is_done = 1; | ||||
|             return ret; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* reallocate the buffer for the decoded samples, if necessary */ | ||||
|     samples_size = | ||||
|         FFMAX(movie->pkt.size*sizeof(movie->bps), AVCODEC_MAX_AUDIO_FRAME_SIZE); | ||||
|     if (samples_size > movie->samples_buf_size) { | ||||
|         movie->samples_buf = av_fast_realloc(movie->samples_buf, | ||||
|                                              &movie->samples_buf_size, samples_size); | ||||
|         if (!movie->samples_buf) | ||||
|             return AVERROR(ENOMEM); | ||||
|     } | ||||
|     decoded_data_size = movie->samples_buf_size; | ||||
|  | ||||
|     /* decode and update the movie pkt */ | ||||
|     ret = avcodec_decode_audio3(movie->codec_ctx, movie->samples_buf, | ||||
|                                 &decoded_data_size, &movie->pkt); | ||||
|     if (ret < 0) | ||||
|         return ret; | ||||
|     movie->pkt.data += ret; | ||||
|     movie->pkt.size -= ret; | ||||
|  | ||||
|     /* wrap the decoded data in a samplesref */ | ||||
|     if (decoded_data_size > 0) { | ||||
|         int nb_samples = decoded_data_size / movie->bps / movie->codec_ctx->channels; | ||||
|         movie->samplesref = | ||||
|             avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, | ||||
|                                       movie->codec_ctx->sample_fmt, nb_samples, | ||||
|                                       movie->codec_ctx->channel_layout, 0); | ||||
|         memcpy(movie->samplesref->data[0], movie->samples_buf, decoded_data_size); | ||||
|         movie->samplesref->pts = movie->pkt.pts; | ||||
|         movie->samplesref->pos = movie->pkt.pos; | ||||
|         movie->samplesref->audio->sample_rate = movie->codec_ctx->sample_rate; | ||||
|     } | ||||
|  | ||||
|     // We got it. Free the packet since we are returning | ||||
|     if (movie->pkt.size <= 0) | ||||
|         av_free_packet(&movie->pkt0); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int amovie_request_frame(AVFilterLink *outlink) | ||||
| { | ||||
|     MovieContext *movie = outlink->src->priv; | ||||
|     int ret; | ||||
|  | ||||
|     if (movie->is_done) | ||||
|         return AVERROR_EOF; | ||||
|     if ((ret = amovie_get_samples(outlink)) < 0) | ||||
|         return ret; | ||||
|  | ||||
|     avfilter_filter_samples(outlink, avfilter_ref_buffer(movie->samplesref, ~0)); | ||||
|     avfilter_unref_buffer(movie->samplesref); | ||||
|     movie->samplesref = NULL; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| AVFilter avfilter_asrc_amovie = { | ||||
|     .name          = "amovie", | ||||
|     .description   = NULL_IF_CONFIG_SMALL("Read audio from a movie source."), | ||||
|     .priv_size     = sizeof(MovieContext), | ||||
|     .init          = amovie_init, | ||||
|     .uninit        = movie_common_uninit, | ||||
|     .query_formats = amovie_query_formats, | ||||
|  | ||||
|     .inputs    = (AVFilterPad[]) {{ .name = NULL }}, | ||||
|     .outputs   = (AVFilterPad[]) {{ .name            = "default", | ||||
|                                     .type            = AVMEDIA_TYPE_AUDIO, | ||||
|                                     .request_frame   = amovie_request_frame, | ||||
|                                     .config_props    = amovie_config_output_props, }, | ||||
|                                   { .name = NULL}}, | ||||
| }; | ||||
|  | ||||
| #endif /* CONFIG_AMOVIE_FILTER */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user