1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2017 Jun Zhao 3cabdff1aSopenharmony_ci * Copyright (c) 2017 Kaixuan Liu 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * HW Acceleration API (video decoding) decode sample 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 8cabdff1aSopenharmony_ci * of this software and associated documentation files (the "Software"), to deal 9cabdff1aSopenharmony_ci * in the Software without restriction, including without limitation the rights 10cabdff1aSopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11cabdff1aSopenharmony_ci * copies of the Software, and to permit persons to whom the Software is 12cabdff1aSopenharmony_ci * furnished to do so, subject to the following conditions: 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * The above copyright notice and this permission notice shall be included in 15cabdff1aSopenharmony_ci * all copies or substantial portions of the Software. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18cabdff1aSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19cabdff1aSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20cabdff1aSopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21cabdff1aSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22cabdff1aSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23cabdff1aSopenharmony_ci * THE SOFTWARE. 24cabdff1aSopenharmony_ci */ 25cabdff1aSopenharmony_ci 26cabdff1aSopenharmony_ci/** 27cabdff1aSopenharmony_ci * @file 28cabdff1aSopenharmony_ci * HW-Accelerated decoding example. 29cabdff1aSopenharmony_ci * 30cabdff1aSopenharmony_ci * @example hw_decode.c 31cabdff1aSopenharmony_ci * This example shows how to do HW-accelerated decoding with output 32cabdff1aSopenharmony_ci * frames from the HW video surfaces. 33cabdff1aSopenharmony_ci */ 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci#include <stdio.h> 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci#include <libavcodec/avcodec.h> 38cabdff1aSopenharmony_ci#include <libavformat/avformat.h> 39cabdff1aSopenharmony_ci#include <libavutil/pixdesc.h> 40cabdff1aSopenharmony_ci#include <libavutil/hwcontext.h> 41cabdff1aSopenharmony_ci#include <libavutil/opt.h> 42cabdff1aSopenharmony_ci#include <libavutil/avassert.h> 43cabdff1aSopenharmony_ci#include <libavutil/imgutils.h> 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_cistatic AVBufferRef *hw_device_ctx = NULL; 46cabdff1aSopenharmony_cistatic enum AVPixelFormat hw_pix_fmt; 47cabdff1aSopenharmony_cistatic FILE *output_file = NULL; 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_cistatic int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) 50cabdff1aSopenharmony_ci{ 51cabdff1aSopenharmony_ci int err = 0; 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci if ((err = av_hwdevice_ctx_create(&hw_device_ctx, type, 54cabdff1aSopenharmony_ci NULL, NULL, 0)) < 0) { 55cabdff1aSopenharmony_ci fprintf(stderr, "Failed to create specified HW device.\n"); 56cabdff1aSopenharmony_ci return err; 57cabdff1aSopenharmony_ci } 58cabdff1aSopenharmony_ci ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx); 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci return err; 61cabdff1aSopenharmony_ci} 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_cistatic enum AVPixelFormat get_hw_format(AVCodecContext *ctx, 64cabdff1aSopenharmony_ci const enum AVPixelFormat *pix_fmts) 65cabdff1aSopenharmony_ci{ 66cabdff1aSopenharmony_ci const enum AVPixelFormat *p; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci for (p = pix_fmts; *p != -1; p++) { 69cabdff1aSopenharmony_ci if (*p == hw_pix_fmt) 70cabdff1aSopenharmony_ci return *p; 71cabdff1aSopenharmony_ci } 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_ci fprintf(stderr, "Failed to get HW surface format.\n"); 74cabdff1aSopenharmony_ci return AV_PIX_FMT_NONE; 75cabdff1aSopenharmony_ci} 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_cistatic int decode_write(AVCodecContext *avctx, AVPacket *packet) 78cabdff1aSopenharmony_ci{ 79cabdff1aSopenharmony_ci AVFrame *frame = NULL, *sw_frame = NULL; 80cabdff1aSopenharmony_ci AVFrame *tmp_frame = NULL; 81cabdff1aSopenharmony_ci uint8_t *buffer = NULL; 82cabdff1aSopenharmony_ci int size; 83cabdff1aSopenharmony_ci int ret = 0; 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_ci ret = avcodec_send_packet(avctx, packet); 86cabdff1aSopenharmony_ci if (ret < 0) { 87cabdff1aSopenharmony_ci fprintf(stderr, "Error during decoding\n"); 88cabdff1aSopenharmony_ci return ret; 89cabdff1aSopenharmony_ci } 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci while (1) { 92cabdff1aSopenharmony_ci if (!(frame = av_frame_alloc()) || !(sw_frame = av_frame_alloc())) { 93cabdff1aSopenharmony_ci fprintf(stderr, "Can not alloc frame\n"); 94cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 95cabdff1aSopenharmony_ci goto fail; 96cabdff1aSopenharmony_ci } 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci ret = avcodec_receive_frame(avctx, frame); 99cabdff1aSopenharmony_ci if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { 100cabdff1aSopenharmony_ci av_frame_free(&frame); 101cabdff1aSopenharmony_ci av_frame_free(&sw_frame); 102cabdff1aSopenharmony_ci return 0; 103cabdff1aSopenharmony_ci } else if (ret < 0) { 104cabdff1aSopenharmony_ci fprintf(stderr, "Error while decoding\n"); 105cabdff1aSopenharmony_ci goto fail; 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci if (frame->format == hw_pix_fmt) { 109cabdff1aSopenharmony_ci /* retrieve data from GPU to CPU */ 110cabdff1aSopenharmony_ci if ((ret = av_hwframe_transfer_data(sw_frame, frame, 0)) < 0) { 111cabdff1aSopenharmony_ci fprintf(stderr, "Error transferring the data to system memory\n"); 112cabdff1aSopenharmony_ci goto fail; 113cabdff1aSopenharmony_ci } 114cabdff1aSopenharmony_ci tmp_frame = sw_frame; 115cabdff1aSopenharmony_ci } else 116cabdff1aSopenharmony_ci tmp_frame = frame; 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci size = av_image_get_buffer_size(tmp_frame->format, tmp_frame->width, 119cabdff1aSopenharmony_ci tmp_frame->height, 1); 120cabdff1aSopenharmony_ci buffer = av_malloc(size); 121cabdff1aSopenharmony_ci if (!buffer) { 122cabdff1aSopenharmony_ci fprintf(stderr, "Can not alloc buffer\n"); 123cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 124cabdff1aSopenharmony_ci goto fail; 125cabdff1aSopenharmony_ci } 126cabdff1aSopenharmony_ci ret = av_image_copy_to_buffer(buffer, size, 127cabdff1aSopenharmony_ci (const uint8_t * const *)tmp_frame->data, 128cabdff1aSopenharmony_ci (const int *)tmp_frame->linesize, tmp_frame->format, 129cabdff1aSopenharmony_ci tmp_frame->width, tmp_frame->height, 1); 130cabdff1aSopenharmony_ci if (ret < 0) { 131cabdff1aSopenharmony_ci fprintf(stderr, "Can not copy image to buffer\n"); 132cabdff1aSopenharmony_ci goto fail; 133cabdff1aSopenharmony_ci } 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci if ((ret = fwrite(buffer, 1, size, output_file)) < 0) { 136cabdff1aSopenharmony_ci fprintf(stderr, "Failed to dump raw data.\n"); 137cabdff1aSopenharmony_ci goto fail; 138cabdff1aSopenharmony_ci } 139cabdff1aSopenharmony_ci 140cabdff1aSopenharmony_ci fail: 141cabdff1aSopenharmony_ci av_frame_free(&frame); 142cabdff1aSopenharmony_ci av_frame_free(&sw_frame); 143cabdff1aSopenharmony_ci av_freep(&buffer); 144cabdff1aSopenharmony_ci if (ret < 0) 145cabdff1aSopenharmony_ci return ret; 146cabdff1aSopenharmony_ci } 147cabdff1aSopenharmony_ci} 148cabdff1aSopenharmony_ci 149cabdff1aSopenharmony_ciint main(int argc, char *argv[]) 150cabdff1aSopenharmony_ci{ 151cabdff1aSopenharmony_ci AVFormatContext *input_ctx = NULL; 152cabdff1aSopenharmony_ci int video_stream, ret; 153cabdff1aSopenharmony_ci AVStream *video = NULL; 154cabdff1aSopenharmony_ci AVCodecContext *decoder_ctx = NULL; 155cabdff1aSopenharmony_ci const AVCodec *decoder = NULL; 156cabdff1aSopenharmony_ci AVPacket *packet = NULL; 157cabdff1aSopenharmony_ci enum AVHWDeviceType type; 158cabdff1aSopenharmony_ci int i; 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci if (argc < 4) { 161cabdff1aSopenharmony_ci fprintf(stderr, "Usage: %s <device type> <input file> <output file>\n", argv[0]); 162cabdff1aSopenharmony_ci return -1; 163cabdff1aSopenharmony_ci } 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci type = av_hwdevice_find_type_by_name(argv[1]); 166cabdff1aSopenharmony_ci if (type == AV_HWDEVICE_TYPE_NONE) { 167cabdff1aSopenharmony_ci fprintf(stderr, "Device type %s is not supported.\n", argv[1]); 168cabdff1aSopenharmony_ci fprintf(stderr, "Available device types:"); 169cabdff1aSopenharmony_ci while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) 170cabdff1aSopenharmony_ci fprintf(stderr, " %s", av_hwdevice_get_type_name(type)); 171cabdff1aSopenharmony_ci fprintf(stderr, "\n"); 172cabdff1aSopenharmony_ci return -1; 173cabdff1aSopenharmony_ci } 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci packet = av_packet_alloc(); 176cabdff1aSopenharmony_ci if (!packet) { 177cabdff1aSopenharmony_ci fprintf(stderr, "Failed to allocate AVPacket\n"); 178cabdff1aSopenharmony_ci return -1; 179cabdff1aSopenharmony_ci } 180cabdff1aSopenharmony_ci 181cabdff1aSopenharmony_ci /* open the input file */ 182cabdff1aSopenharmony_ci if (avformat_open_input(&input_ctx, argv[2], NULL, NULL) != 0) { 183cabdff1aSopenharmony_ci fprintf(stderr, "Cannot open input file '%s'\n", argv[2]); 184cabdff1aSopenharmony_ci return -1; 185cabdff1aSopenharmony_ci } 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci if (avformat_find_stream_info(input_ctx, NULL) < 0) { 188cabdff1aSopenharmony_ci fprintf(stderr, "Cannot find input stream information.\n"); 189cabdff1aSopenharmony_ci return -1; 190cabdff1aSopenharmony_ci } 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci /* find the video stream information */ 193cabdff1aSopenharmony_ci ret = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); 194cabdff1aSopenharmony_ci if (ret < 0) { 195cabdff1aSopenharmony_ci fprintf(stderr, "Cannot find a video stream in the input file\n"); 196cabdff1aSopenharmony_ci return -1; 197cabdff1aSopenharmony_ci } 198cabdff1aSopenharmony_ci video_stream = ret; 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci for (i = 0;; i++) { 201cabdff1aSopenharmony_ci const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i); 202cabdff1aSopenharmony_ci if (!config) { 203cabdff1aSopenharmony_ci fprintf(stderr, "Decoder %s does not support device type %s.\n", 204cabdff1aSopenharmony_ci decoder->name, av_hwdevice_get_type_name(type)); 205cabdff1aSopenharmony_ci return -1; 206cabdff1aSopenharmony_ci } 207cabdff1aSopenharmony_ci if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && 208cabdff1aSopenharmony_ci config->device_type == type) { 209cabdff1aSopenharmony_ci hw_pix_fmt = config->pix_fmt; 210cabdff1aSopenharmony_ci break; 211cabdff1aSopenharmony_ci } 212cabdff1aSopenharmony_ci } 213cabdff1aSopenharmony_ci 214cabdff1aSopenharmony_ci if (!(decoder_ctx = avcodec_alloc_context3(decoder))) 215cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 216cabdff1aSopenharmony_ci 217cabdff1aSopenharmony_ci video = input_ctx->streams[video_stream]; 218cabdff1aSopenharmony_ci if (avcodec_parameters_to_context(decoder_ctx, video->codecpar) < 0) 219cabdff1aSopenharmony_ci return -1; 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci decoder_ctx->get_format = get_hw_format; 222cabdff1aSopenharmony_ci 223cabdff1aSopenharmony_ci if (hw_decoder_init(decoder_ctx, type) < 0) 224cabdff1aSopenharmony_ci return -1; 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) { 227cabdff1aSopenharmony_ci fprintf(stderr, "Failed to open codec for stream #%u\n", video_stream); 228cabdff1aSopenharmony_ci return -1; 229cabdff1aSopenharmony_ci } 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci /* open the file to dump raw data */ 232cabdff1aSopenharmony_ci output_file = fopen(argv[3], "w+b"); 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_ci /* actual decoding and dump the raw data */ 235cabdff1aSopenharmony_ci while (ret >= 0) { 236cabdff1aSopenharmony_ci if ((ret = av_read_frame(input_ctx, packet)) < 0) 237cabdff1aSopenharmony_ci break; 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci if (video_stream == packet->stream_index) 240cabdff1aSopenharmony_ci ret = decode_write(decoder_ctx, packet); 241cabdff1aSopenharmony_ci 242cabdff1aSopenharmony_ci av_packet_unref(packet); 243cabdff1aSopenharmony_ci } 244cabdff1aSopenharmony_ci 245cabdff1aSopenharmony_ci /* flush the decoder */ 246cabdff1aSopenharmony_ci ret = decode_write(decoder_ctx, NULL); 247cabdff1aSopenharmony_ci 248cabdff1aSopenharmony_ci if (output_file) 249cabdff1aSopenharmony_ci fclose(output_file); 250cabdff1aSopenharmony_ci av_packet_free(&packet); 251cabdff1aSopenharmony_ci avcodec_free_context(&decoder_ctx); 252cabdff1aSopenharmony_ci avformat_close_input(&input_ctx); 253cabdff1aSopenharmony_ci av_buffer_unref(&hw_device_ctx); 254cabdff1aSopenharmony_ci 255cabdff1aSopenharmony_ci return 0; 256cabdff1aSopenharmony_ci} 257