You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	avformat/utils: parse some stream specifiers recursively
This removes lots of code duplication and also allows more complex specifiers, for example you can use p:204:aⓂ️language:eng to select the English language audio stream from program 204. Signed-off-by: Marton Balint <cus@passwd.hu>
This commit is contained in:
		| @@ -34,27 +34,21 @@ Possible forms of stream specifiers are: | ||||
| @table @option | ||||
| @item @var{stream_index} | ||||
| Matches the stream with this index. E.g. @code{-threads:1 4} would set the | ||||
| thread count for the second stream to 4. | ||||
| @item @var{stream_type}[:@var{stream_index}] | ||||
| thread count for the second stream to 4. If @var{stream_index} is used as an | ||||
| additional stream specifier (see below), then it selects stream number | ||||
| @var{stream_index} from the matching streams. | ||||
| @item @var{stream_type}[:@var{additional_stream_specifier}] | ||||
| @var{stream_type} is one of following: 'v' or 'V' for video, 'a' for audio, 's' | ||||
| for subtitle, 'd' for data, and 't' for attachments. 'v' matches all video | ||||
| streams, 'V' only matches video streams which are not attached pictures, video | ||||
| thumbnails or cover arts.  If @var{stream_index} is given, then it matches | ||||
| stream number @var{stream_index} of this type. Otherwise, it matches all | ||||
| streams of this type. | ||||
| @item p:@var{program_id}[:@var{stream_index}] or p:@var{program_id}[:@var{stream_type}[:@var{stream_index}]] or | ||||
| p:@var{program_id}:m:@var{key}[:@var{value}] | ||||
| In first version, if @var{stream_index} is given, then it matches the stream with number @var{stream_index} | ||||
| in the program with the id @var{program_id}. Otherwise, it matches all streams in the | ||||
| program. In the second version, @var{stream_type} is one of following: 'v' for video, 'a' for audio, 's' | ||||
| for subtitle, 'd' for data. If @var{stream_index} is also given, then it matches | ||||
| stream number @var{stream_index} of this type in the program with the id @var{program_id}. | ||||
| Otherwise, if only @var{stream_type} is given, it matches all | ||||
| streams of this type in the program with the id @var{program_id}. | ||||
| In the third version matches streams in the program with the id @var{program_id} with the metadata | ||||
| tag @var{key} having the specified value. If | ||||
| @var{value} is not given, matches streams that contain the given tag with any | ||||
| value. | ||||
| thumbnails or cover arts. If @var{additional_stream_specifier} is used, then | ||||
| it matches streams which both have this type and match the | ||||
| @var{additional_stream_specifier}. Otherwise, it matches all streams of the | ||||
| specified type. | ||||
| @item p:@var{program_id}[:@var{additional_stream_specifier}] | ||||
| Matches streams which are in the program with the id @var{program_id}. If | ||||
| @var{additional_stream_specifier} is used, then it matches streams which both | ||||
| are part of the program and match the @var{additional_stream_specifier}. | ||||
|  | ||||
| @item #@var{stream_id} or i:@var{stream_id} | ||||
| Match the stream by stream id (e.g. PID in MPEG-TS container). | ||||
|   | ||||
| @@ -5097,13 +5097,24 @@ AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *f | ||||
|     return fr; | ||||
| } | ||||
|  | ||||
| int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, | ||||
|                                     const char *spec) | ||||
| /** | ||||
|  * Matches a stream specifier (but ignores requested index). | ||||
|  * | ||||
|  * @param index set if a specific index is requested from the matching streams | ||||
|  * | ||||
|  * @return <0 on error | ||||
|  *         0  if st is NOT a matching stream | ||||
|  *         >0 if st is a matching stream | ||||
|  */ | ||||
| static int match_stream_specifier(AVFormatContext *s, AVStream *st, | ||||
|                                   const char *spec, int *index) | ||||
| { | ||||
|     if (*spec <= '9' && *spec >= '0') /* opt:index */ | ||||
|         return strtol(spec, NULL, 0) == st->index; | ||||
|     else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || | ||||
|              *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ | ||||
|     if (*spec <= '9' && *spec >= '0') { /* opt:index */ | ||||
|         if (index) | ||||
|             *index = strtol(spec, NULL, 0); | ||||
|         return 1; | ||||
|     } else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || | ||||
|                *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ | ||||
|         enum AVMediaType type; | ||||
|         int nopic = 0; | ||||
|  | ||||
| @@ -5128,27 +5139,8 @@ FF_ENABLE_DEPRECATION_WARNINGS | ||||
| #endif | ||||
|         if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) | ||||
|             return 0; | ||||
|         if (*spec++ == ':') { /* possibly followed by :index */ | ||||
|             int i, index = strtol(spec, NULL, 0); | ||||
|             for (i = 0; i < s->nb_streams; i++) { | ||||
| #if FF_API_LAVF_AVCTX | ||||
| FF_DISABLE_DEPRECATION_WARNINGS | ||||
|                 if ((s->streams[i]->codecpar->codec_type == type | ||||
|                       || s->streams[i]->codec->codec_type == type | ||||
|                     ) && | ||||
|                     !(nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && | ||||
|                     index-- == 0) | ||||
|                     return i == st->index; | ||||
| FF_ENABLE_DEPRECATION_WARNINGS | ||||
| #else | ||||
|                 if ((s->streams[i]->codecpar->codec_type == type) && | ||||
|                     !(nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && | ||||
|                     index-- == 0) | ||||
|                     return i == st->index; | ||||
| #endif | ||||
|             } | ||||
|             return 0; | ||||
|         } | ||||
|         if (*spec++ == ':') /* possibly followed by another specifier */ | ||||
|             return match_stream_specifier(s, st, spec, index); | ||||
|         return 1; | ||||
|     } else if (*spec == 'p' && *(spec + 1) == ':') { | ||||
|         int prog_id, i, j; | ||||
| @@ -5159,99 +5151,15 @@ FF_ENABLE_DEPRECATION_WARNINGS | ||||
|             if (s->programs[i]->id != prog_id) | ||||
|                 continue; | ||||
|  | ||||
|             if (*endptr++ == ':') {  // p:<id>:.... | ||||
|                 if ( *endptr == 'a' || *endptr == 'v' || | ||||
|                      *endptr == 's' || *endptr == 'd') {  // p:<id>:<st_type>[:<index>] | ||||
|                     enum AVMediaType type; | ||||
|  | ||||
|                     switch (*endptr++) { | ||||
|                     case 'v': type = AVMEDIA_TYPE_VIDEO;      break; | ||||
|                     case 'a': type = AVMEDIA_TYPE_AUDIO;      break; | ||||
|                     case 's': type = AVMEDIA_TYPE_SUBTITLE;   break; | ||||
|                     case 'd': type = AVMEDIA_TYPE_DATA;       break; | ||||
|                     default:  av_assert0(0); | ||||
|             for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) { | ||||
|                 if (st->index == s->programs[i]->stream_index[j]) { | ||||
|                     if (*endptr++ == ':') {  // p:<id>:.... | ||||
|                         return match_stream_specifier(s, st, endptr, index); | ||||
|                     } else { | ||||
|                         return 1; | ||||
|                     } | ||||
|                     if (*endptr++ == ':') {  // p:<id>:<st_type>:<index> | ||||
|                         int stream_idx = strtol(endptr, NULL, 0), type_counter = 0; | ||||
|                         for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) { | ||||
|                             int stream_index = s->programs[i]->stream_index[j]; | ||||
|                             if (st->index == s->programs[i]->stream_index[j]) { | ||||
| #if FF_API_LAVF_AVCTX | ||||
| FF_DISABLE_DEPRECATION_WARNINGS | ||||
|                                 return type_counter == stream_idx && | ||||
|                                        (type == st->codecpar->codec_type || | ||||
|                                         type == st->codec->codec_type); | ||||
| FF_ENABLE_DEPRECATION_WARNINGS | ||||
| #else | ||||
|                                 return type_counter == stream_idx && | ||||
|                                        type == st->codecpar->codec_type; | ||||
| #endif | ||||
|                              } | ||||
| #if FF_API_LAVF_AVCTX | ||||
| FF_DISABLE_DEPRECATION_WARNINGS | ||||
|                             if (type == s->streams[stream_index]->codecpar->codec_type || | ||||
|                                 type == s->streams[stream_index]->codec->codec_type) | ||||
|                                 type_counter++; | ||||
| FF_ENABLE_DEPRECATION_WARNINGS | ||||
| #else | ||||
|                             if (type == s->streams[stream_index]->codecpar->codec_type) | ||||
|                                 type_counter++; | ||||
| #endif | ||||
|                         } | ||||
|                         return 0; | ||||
|                     } else {  // p:<id>:<st_type> | ||||
|                         for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) | ||||
|                             if (st->index == s->programs[i]->stream_index[j]) { | ||||
| #if FF_API_LAVF_AVCTX | ||||
| FF_DISABLE_DEPRECATION_WARNINGS | ||||
|                                  return type == st->codecpar->codec_type || | ||||
|                                         type == st->codec->codec_type; | ||||
| FF_ENABLE_DEPRECATION_WARNINGS | ||||
| #else | ||||
|                                  return type == st->codecpar->codec_type; | ||||
| #endif | ||||
|                             } | ||||
|                         return 0; | ||||
|                     } | ||||
|  | ||||
|                 } else if ( *endptr == 'm') { // p:<id>:m:<metadata_spec> | ||||
|                     AVDictionaryEntry *tag; | ||||
|                     char *key, *val; | ||||
|                     int ret = 0; | ||||
|  | ||||
|                     if (*(++endptr) != ':') { | ||||
|                         av_log(s, AV_LOG_ERROR, "Invalid stream specifier syntax, missing ':' sign after :m.\n"); | ||||
|                         return AVERROR(EINVAL); | ||||
|                     } | ||||
|  | ||||
|                     val = strchr(++endptr, ':'); | ||||
|                     key = val ? av_strndup(endptr, val - endptr) : av_strdup(endptr); | ||||
|                     if (!key) | ||||
|                         return AVERROR(ENOMEM); | ||||
|  | ||||
|                     for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) | ||||
|                         if (st->index == s->programs[i]->stream_index[j]) { | ||||
|                             tag = av_dict_get(st->metadata, key, NULL, 0); | ||||
|                             if (tag && (!val || !strcmp(tag->value, val + 1))) | ||||
|                                 ret = 1; | ||||
|  | ||||
|                             break; | ||||
|                         } | ||||
|  | ||||
|                     av_freep(&key); | ||||
|                     return ret; | ||||
|  | ||||
|                 } else {  // p:<id>:<index> | ||||
|                     int stream_idx = strtol(endptr, NULL, 0); | ||||
|                     return stream_idx >= 0 && | ||||
|                            stream_idx < s->programs[i]->nb_stream_indexes && | ||||
|                            st->index == s->programs[i]->stream_index[stream_idx]; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) | ||||
|                 if (st->index == s->programs[i]->stream_index[j]) | ||||
|                     return 1; | ||||
|         } | ||||
|         return 0; | ||||
|     } else if (*spec == '#' || | ||||
| @@ -5333,10 +5241,39 @@ FF_ENABLE_DEPRECATION_WARNINGS | ||||
|     } else if (!*spec) /* empty specifier, matches everything */ | ||||
|         return 1; | ||||
|  | ||||
|     av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); | ||||
|     return AVERROR(EINVAL); | ||||
| } | ||||
|  | ||||
|  | ||||
| int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, | ||||
|                                     const char *spec) | ||||
| { | ||||
|     int ret; | ||||
|     int index = -1; | ||||
|  | ||||
|     /* This is not really needed but saves us a loop for simple stream index specifiers. */ | ||||
|     if (*spec <= '9' && *spec >= '0') /* opt:index */ | ||||
|         return strtol(spec, NULL, 0) == st->index; | ||||
|  | ||||
|     ret = match_stream_specifier(s, st, spec, &index); | ||||
|     if (ret < 0) { | ||||
|         av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); | ||||
|         return ret; | ||||
|     } | ||||
|     if (!ret || index < 0) | ||||
|         return ret; | ||||
|  | ||||
|     /* If we requested a matching stream index, we have to ensure st is that. */ | ||||
|     for (int i = 0; i < s->nb_streams && index >= 0; i++) { | ||||
|         int ret = match_stream_specifier(s, s->streams[i], spec, NULL); | ||||
|         if (ret < 0) | ||||
|             return ret; | ||||
|         if (ret > 0 && index-- == 0 && st == s->streams[i]) | ||||
|             return 1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int ff_generate_avci_extradata(AVStream *st) | ||||
| { | ||||
|     static const uint8_t avci100_1080p_extradata[] = { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user