int main(int argc, char *argv[]) { AVFormatContext *input_ctx = NULL; int video_stream, ret; AVStream *video = NULL; AVCodecContext *decoder_ctx = NULL; AVCodec *decoder = NULL; AVPacket packet; enum AVHWDeviceType type; int i; if (argc < 4) { fprintf(stderr, "Usage: %s <device type> <input file> <output file>\n", argv[0]); return -1; } type = av_hwdevice_find_type_by_name(argv[1]); if (type == AV_HWDEVICE_TYPE_NONE) { fprintf(stderr, "Device type %s is not supported.\n", argv[1]); fprintf(stderr, "Available device types:"); while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) fprintf(stderr, " %s", av_hwdevice_get_type_name(type)); fprintf(stderr, "\n"); return -1; } /* open the input file */ if (avformat_open_input(&input_ctx, argv[2], NULL, NULL) != 0) { fprintf(stderr, "Cannot open input file '%s'\n", argv[2]); return -1; } if (avformat_find_stream_info(input_ctx, NULL) < 0) { fprintf(stderr, "Cannot find input stream information.\n"); return -1; } /* find the video stream information */ ret = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); if (ret < 0) { fprintf(stderr, "Cannot find a video stream in the input file\n"); return -1; } video_stream = ret; for (i = 0;; i++) { const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i); if (!config) { fprintf(stderr, "Decoder %s does not support device type %s.\n", decoder->name, av_hwdevice_get_type_name(type)); return -1; } if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) { hw_pix_fmt = config->pix_fmt; break; } } if (!(decoder_ctx = avcodec_alloc_context3(decoder))) return AVERROR(ENOMEM); video = input_ctx->streams[video_stream]; if (avcodec_parameters_to_context(decoder_ctx, video->codecpar) < 0) return -1; decoder_ctx->get_format = get_hw_format; av_opt_set_int(decoder_ctx, "refcounted_frames", 1, 0); if (hw_decoder_init(decoder_ctx, type) < 0) return -1; if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) { fprintf(stderr, "Failed to open codec for stream #%u\n", video_stream); return -1; } /* open the file to dump raw data */ output_file = fopen(argv[3], "w+"); /* actual decoding and dump the raw data */ while (ret >= 0) { if ((ret = av_read_frame(input_ctx, &packet)) < 0) break; if (video_stream == packet.stream_index) ret = decode_write(decoder_ctx, &packet); av_packet_unref(&packet); } /* flush the decoder */ packet.data = NULL; packet.size = 0; ret = decode_write(decoder_ctx, &packet); av_packet_unref(&packet); if (output_file) fclose(output_file); avcodec_free_context(&decoder_ctx); avformat_close_input(&input_ctx); av_buffer_unref(&hw_device_ctx); return 0; }
static int hwmap_config_output(AVFilterLink *outlink) { AVFilterContext *avctx = outlink->src; HWMapContext *ctx = avctx->priv; AVFilterLink *inlink = avctx->inputs[0]; AVHWFramesContext *hwfc; AVBufferRef *device; const AVPixFmtDescriptor *desc; int err; av_log(avctx, AV_LOG_DEBUG, "Configure hwmap %s -> %s.\n", av_get_pix_fmt_name(inlink->format), av_get_pix_fmt_name(outlink->format)); av_buffer_unref(&ctx->hwframes_ref); device = avctx->hw_device_ctx; if (inlink->hw_frames_ctx) { hwfc = (AVHWFramesContext*)inlink->hw_frames_ctx->data; if (ctx->derive_device_type) { enum AVHWDeviceType type; type = av_hwdevice_find_type_by_name(ctx->derive_device_type); if (type == AV_HWDEVICE_TYPE_NONE) { av_log(avctx, AV_LOG_ERROR, "Invalid device type.\n"); goto fail; } err = av_hwdevice_ctx_create_derived(&device, type, hwfc->device_ref, 0); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to created derived " "device context: %d.\n", err); goto fail; } } desc = av_pix_fmt_desc_get(outlink->format); if (!desc) { err = AVERROR(EINVAL); goto fail; } if (inlink->format == hwfc->format && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) && !ctx->reverse) { // Map between two hardware formats (including the case of // undoing an existing mapping). if (!device) { av_log(avctx, AV_LOG_ERROR, "A device reference is " "required to map to a hardware format.\n"); err = AVERROR(EINVAL); goto fail; } err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref, outlink->format, device, inlink->hw_frames_ctx, 0); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create derived " "frames context: %d.\n", err); goto fail; } } else if (inlink->format == hwfc->format && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) && ctx->reverse) { // Map between two hardware formats, but do it in reverse. // Make a new hwframe context for the target type, and then // overwrite the input hwframe context with a derived context // mapped from that back to the source type. AVBufferRef *source; AVHWFramesContext *frames; ctx->hwframes_ref = av_hwframe_ctx_alloc(device); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; } frames = (AVHWFramesContext*)ctx->hwframes_ref->data; frames->format = outlink->format; frames->sw_format = hwfc->sw_format; frames->width = hwfc->width; frames->height = hwfc->height; frames->initial_pool_size = 64; err = av_hwframe_ctx_init(ctx->hwframes_ref); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to initialise " "target frames context: %d.\n", err); goto fail; } err = av_hwframe_ctx_create_derived(&source, inlink->format, hwfc->device_ref, ctx->hwframes_ref, ctx->mode); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create " "derived source frames context: %d.\n", err); goto fail; } // Here is the naughty bit. This overwriting changes what // ff_get_video_buffer() in the previous filter returns - // it will now give a frame allocated here mapped back to // the format it expects. If there were any additional // constraints on the output frames there then this may // break nastily. av_buffer_unref(&inlink->hw_frames_ctx); inlink->hw_frames_ctx = source; } else if ((outlink->format == hwfc->format && inlink->format == hwfc->sw_format) || inlink->format == hwfc->format) { // Map from a hardware format to a software format, or // undo an existing such mapping. ctx->hwframes_ref = av_buffer_ref(inlink->hw_frames_ctx); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; } } else { // Non-matching formats - not supported. av_log(avctx, AV_LOG_ERROR, "Unsupported formats for " "hwmap: from %s (%s) to %s.\n", av_get_pix_fmt_name(inlink->format), av_get_pix_fmt_name(hwfc->format), av_get_pix_fmt_name(outlink->format)); err = AVERROR(EINVAL); goto fail; } } else if (avctx->hw_device_ctx) { // Map from a software format to a hardware format. This // creates a new hwframe context like hwupload, but then // returns frames mapped from that to the previous link in // order to fill them without an additional copy. if (!device) { av_log(avctx, AV_LOG_ERROR, "A device reference is " "required to create new frames with reverse " "mapping.\n"); err = AVERROR(EINVAL); goto fail; } ctx->reverse = 1; ctx->hwframes_ref = av_hwframe_ctx_alloc(device); if (!ctx->hwframes_ref) { err = AVERROR(ENOMEM); goto fail; } hwfc = (AVHWFramesContext*)ctx->hwframes_ref->data; hwfc->format = outlink->format; hwfc->sw_format = inlink->format; hwfc->width = inlink->w; hwfc->height = inlink->h; err = av_hwframe_ctx_init(ctx->hwframes_ref); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create frame " "context for reverse mapping: %d.\n", err); goto fail; } } else { av_log(avctx, AV_LOG_ERROR, "Mapping requires a hardware " "context (a device, or frames on input).\n"); return AVERROR(EINVAL); } outlink->hw_frames_ctx = av_buffer_ref(ctx->hwframes_ref); if (!outlink->hw_frames_ctx) { err = AVERROR(ENOMEM); goto fail; } outlink->w = inlink->w; outlink->h = inlink->h; return 0; fail: av_buffer_unref(&ctx->hwframes_ref); return err; }