diff options
author | Matthieu Bouron <matthieu.bouron@stupeflix.com> | 2015-11-25 10:30:15 +0100 |
---|---|---|
committer | Matthieu Bouron <matthieu.bouron@stupeflix.com> | 2015-11-26 17:05:54 +0100 |
commit | 39290f271550c762cb4553e7c8405d344d630d36 (patch) | |
tree | 422b673137a7789d49d7f5154038827a9ff093c3 /tests/api | |
parent | 74b79dcf510b1897ba0d87415e4bac33ca11c024 (diff) | |
download | ffmpeg-39290f271550c762cb4553e7c8405d344d630d36.tar.gz |
fate: add FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM tests
Diffstat (limited to 'tests/api')
-rw-r--r-- | tests/api/Makefile | 1 | ||||
-rw-r--r-- | tests/api/api-codec-param-test.c | 252 |
2 files changed, 253 insertions, 0 deletions
diff --git a/tests/api/Makefile b/tests/api/Makefile index 27f499fd4e..c48c34a413 100644 --- a/tests/api/Makefile +++ b/tests/api/Makefile @@ -1,6 +1,7 @@ APITESTPROGS-$(call ENCDEC, FLAC, FLAC) += api-flac APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264 APITESTPROGS-yes += api-seek +APITESTPROGS-yes += api-codec-param APITESTPROGS-$(call DEMDEC, H263, H263) += api-band APITESTPROGS += $(APITESTPROGS-yes) diff --git a/tests/api/api-codec-param-test.c b/tests/api/api-codec-param-test.c new file mode 100644 index 0000000000..9989825895 --- /dev/null +++ b/tests/api/api-codec-param-test.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2015 Matthieu Bouron <matthieu.bouron stupeflix.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include "libavformat/avformat.h" +#include "libavutil/pixdesc.h" +#include "libavcodec/internal.h" +#include "libavutil/avassert.h" +#include "libavutil/opt.h" + +static int try_decode_video_frame(AVCodecContext *codec_ctx, AVPacket *pkt, int decode) +{ + int ret = 0; + int got_frame = 0; + AVFrame *frame = NULL; + int skip_frame = codec_ctx->skip_frame; + + if (!avcodec_is_open(codec_ctx)) { + const AVCodec *codec = avcodec_find_decoder(codec_ctx->codec_id); + + ret = avcodec_open2(codec_ctx, codec, NULL); + if (ret < 0) { + av_log(codec_ctx, AV_LOG_ERROR, "Failed to open codec\n"); + goto end; + } + } + + frame = av_frame_alloc(); + if (!frame) { + av_log(NULL, AV_LOG_ERROR, "Failed to allocate frame\n"); + goto end; + } + + if (!decode && codec_ctx->codec->caps_internal & FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM) { + codec_ctx->skip_frame = AVDISCARD_ALL; + } + + do { + ret = avcodec_decode_video2(codec_ctx, frame, &got_frame, pkt); + av_assert0(decode || (!decode && !got_frame)); + if (ret < 0) + break; + pkt->data += ret; + pkt->size -= ret; + + if (got_frame) { + break; + } + } while (pkt->size > 0); + +end: + codec_ctx->skip_frame = skip_frame; + + av_frame_free(&frame); + return ret; +} + +static int find_video_stream_info(AVFormatContext *fmt_ctx, int decode) +{ + int ret = 0; + int i, done = 0; + AVPacket pkt; + + av_init_packet(&pkt); + + while (!done) { + AVCodecContext *codec_ctx = NULL; + AVStream *st; + + if ((ret = av_read_frame(fmt_ctx, &pkt)) < 0) { + av_log(fmt_ctx, AV_LOG_ERROR, "Failed to read frame\n"); + goto end; + } + + st = fmt_ctx->streams[pkt.stream_index]; + codec_ctx = st->codec; + + /* Writing to AVStream.codec_info_nb_frames must not be done by + * user applications. It is done here for testing purposing as + * find_video_stream_info tries to mimic avformat_find_stream_info + * which writes to this field. + * */ + if (codec_ctx->codec_type != AVMEDIA_TYPE_VIDEO || + st->codec_info_nb_frames++ > 0) { + av_packet_unref(&pkt); + continue; + } + + ret = try_decode_video_frame(codec_ctx, &pkt, decode); + if (ret < 0) { + av_log(fmt_ctx, AV_LOG_ERROR, "Failed to decode video frame\n"); + goto end; + } + + av_packet_unref(&pkt); + + /* check if all video streams have demuxed a packet */ + done = 1; + for (i = 0; i < fmt_ctx->nb_streams; i++) { + st = fmt_ctx->streams[i]; + codec_ctx = st->codec; + + if (codec_ctx->codec_type != AVMEDIA_TYPE_VIDEO) + continue; + + done &= st->codec_info_nb_frames > 0; + } + } + +end: + av_packet_unref(&pkt); + + return ret < 0; +} + +static void dump_video_streams(const AVFormatContext *fmt_ctx, int decode) +{ + int i; + + for (i = 0; i < fmt_ctx->nb_streams; i++) { + const AVOption *opt = NULL; + const AVStream *st = fmt_ctx->streams[i]; + AVCodecContext *codec_ctx = st->codec; + + printf("stream=%d, decode=%d\n", i, decode); + while (opt = av_opt_next(codec_ctx, opt)) { + uint8_t *str; + + if (opt->type == AV_OPT_TYPE_CONST) + continue; + + if (!strcmp(opt->name, "frame_number")) + continue; + + if (av_opt_get(codec_ctx, opt->name, 0, &str) >= 0) { + printf(" %s=%s\n", opt->name, str); + av_free(str); + } + } + } +} + +static int open_and_probe_video_streams(AVFormatContext **fmt_ctx, const char *filename, int decode) +{ + int ret = 0; + + ret = avformat_open_input(fmt_ctx, filename, NULL, NULL); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to open input '%s'", filename); + goto end; + } + + ret = find_video_stream_info(*fmt_ctx, decode); + if (ret < 0) { + goto end; + } + + dump_video_streams(*fmt_ctx, decode); + +end: + return ret; +} + +static int check_video_streams(const AVFormatContext *fmt_ctx1, const AVFormatContext *fmt_ctx2) +{ + int i; + int ret = 0; + + av_assert0(fmt_ctx1->nb_streams == fmt_ctx2->nb_streams); + for (i = 0; i < fmt_ctx1->nb_streams; i++) { + const AVOption *opt = NULL; + const AVStream *st1 = fmt_ctx1->streams[i]; + const AVStream *st2 = fmt_ctx2->streams[i]; + AVCodecContext *codec_ctx1 = st1->codec; + AVCodecContext *codec_ctx2 = st2->codec; + + if (codec_ctx1->codec_type != AVMEDIA_TYPE_VIDEO) + continue; + + while (opt = av_opt_next(codec_ctx1, opt)) { + uint8_t *str1 = NULL, *str2 = NULL; + + if (opt->type == AV_OPT_TYPE_CONST) + continue; + + if (!strcmp(opt->name, "frame_number")) + continue; + + av_assert0(av_opt_get(codec_ctx1, opt->name, 0, &str1) >= 0); + av_assert0(av_opt_get(codec_ctx2, opt->name, 0, &str2) >= 0); + if (strcmp(str1, str2)) { + av_log(NULL, AV_LOG_ERROR, "Field %s differs: %s %s", opt->name, str1, str2); + ret = AVERROR(EINVAL); + } + av_free(str1); + av_free(str2); + } + } + + return ret; +} + +int main(int argc, char* argv[]) +{ + int ret = 0; + AVFormatContext *fmt_ctx = NULL; + AVFormatContext *fmt_ctx_no_decode = NULL; + + av_register_all(); + + if (argc < 2) { + av_log(NULL, AV_LOG_ERROR, "Usage: %s <input>\n", argv[0]); + return -1; + } + + if ((ret = open_and_probe_video_streams(&fmt_ctx_no_decode, argv[1], 0)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to probe '%s' without frame decoding\n", argv[1]); + goto end; + } + + if ((ret = open_and_probe_video_streams(&fmt_ctx, argv[1], 1)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to probe '%s' with frame decoding\n", argv[1]); + goto end; + } + + ret = check_video_streams(fmt_ctx, fmt_ctx_no_decode); + +end: + avformat_close_input(&fmt_ctx); + avformat_close_input(&fmt_ctx_no_decode); + + return ret; +} |