1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Video Acceleration API (video encoding) encode sample
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
5cabdff1aSopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
6cabdff1aSopenharmony_ci * in the Software without restriction, including without limitation the rights
7cabdff1aSopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8cabdff1aSopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
9cabdff1aSopenharmony_ci * furnished to do so, subject to the following conditions:
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * The above copyright notice and this permission notice shall be included in
12cabdff1aSopenharmony_ci * all copies or substantial portions of the Software.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15cabdff1aSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16cabdff1aSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17cabdff1aSopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18cabdff1aSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19cabdff1aSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20cabdff1aSopenharmony_ci * THE SOFTWARE.
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci/**
24cabdff1aSopenharmony_ci * @file
25cabdff1aSopenharmony_ci * Intel VAAPI-accelerated encoding example.
26cabdff1aSopenharmony_ci *
27cabdff1aSopenharmony_ci * @example vaapi_encode.c
28cabdff1aSopenharmony_ci * This example shows how to do VAAPI-accelerated encoding. now only support NV12
29cabdff1aSopenharmony_ci * raw file, usage like: vaapi_encode 1920 1080 input.yuv output.h264
30cabdff1aSopenharmony_ci *
31cabdff1aSopenharmony_ci */
32cabdff1aSopenharmony_ci
33cabdff1aSopenharmony_ci#include <stdio.h>
34cabdff1aSopenharmony_ci#include <string.h>
35cabdff1aSopenharmony_ci#include <errno.h>
36cabdff1aSopenharmony_ci
37cabdff1aSopenharmony_ci#include <libavcodec/avcodec.h>
38cabdff1aSopenharmony_ci#include <libavutil/pixdesc.h>
39cabdff1aSopenharmony_ci#include <libavutil/hwcontext.h>
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_cistatic int width, height;
42cabdff1aSopenharmony_cistatic AVBufferRef *hw_device_ctx = NULL;
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_cistatic int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx)
45cabdff1aSopenharmony_ci{
46cabdff1aSopenharmony_ci    AVBufferRef *hw_frames_ref;
47cabdff1aSopenharmony_ci    AVHWFramesContext *frames_ctx = NULL;
48cabdff1aSopenharmony_ci    int err = 0;
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci    if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) {
51cabdff1aSopenharmony_ci        fprintf(stderr, "Failed to create VAAPI frame context.\n");
52cabdff1aSopenharmony_ci        return -1;
53cabdff1aSopenharmony_ci    }
54cabdff1aSopenharmony_ci    frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data);
55cabdff1aSopenharmony_ci    frames_ctx->format    = AV_PIX_FMT_VAAPI;
56cabdff1aSopenharmony_ci    frames_ctx->sw_format = AV_PIX_FMT_NV12;
57cabdff1aSopenharmony_ci    frames_ctx->width     = width;
58cabdff1aSopenharmony_ci    frames_ctx->height    = height;
59cabdff1aSopenharmony_ci    frames_ctx->initial_pool_size = 20;
60cabdff1aSopenharmony_ci    if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) {
61cabdff1aSopenharmony_ci        fprintf(stderr, "Failed to initialize VAAPI frame context."
62cabdff1aSopenharmony_ci                "Error code: %s\n",av_err2str(err));
63cabdff1aSopenharmony_ci        av_buffer_unref(&hw_frames_ref);
64cabdff1aSopenharmony_ci        return err;
65cabdff1aSopenharmony_ci    }
66cabdff1aSopenharmony_ci    ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
67cabdff1aSopenharmony_ci    if (!ctx->hw_frames_ctx)
68cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    av_buffer_unref(&hw_frames_ref);
71cabdff1aSopenharmony_ci    return err;
72cabdff1aSopenharmony_ci}
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_cistatic int encode_write(AVCodecContext *avctx, AVFrame *frame, FILE *fout)
75cabdff1aSopenharmony_ci{
76cabdff1aSopenharmony_ci    int ret = 0;
77cabdff1aSopenharmony_ci    AVPacket *enc_pkt;
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_ci    if (!(enc_pkt = av_packet_alloc()))
80cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_ci    if ((ret = avcodec_send_frame(avctx, frame)) < 0) {
83cabdff1aSopenharmony_ci        fprintf(stderr, "Error code: %s\n", av_err2str(ret));
84cabdff1aSopenharmony_ci        goto end;
85cabdff1aSopenharmony_ci    }
86cabdff1aSopenharmony_ci    while (1) {
87cabdff1aSopenharmony_ci        ret = avcodec_receive_packet(avctx, enc_pkt);
88cabdff1aSopenharmony_ci        if (ret)
89cabdff1aSopenharmony_ci            break;
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ci        enc_pkt->stream_index = 0;
92cabdff1aSopenharmony_ci        ret = fwrite(enc_pkt->data, enc_pkt->size, 1, fout);
93cabdff1aSopenharmony_ci        av_packet_unref(enc_pkt);
94cabdff1aSopenharmony_ci    }
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ciend:
97cabdff1aSopenharmony_ci    av_packet_free(&enc_pkt);
98cabdff1aSopenharmony_ci    ret = ((ret == AVERROR(EAGAIN)) ? 0 : -1);
99cabdff1aSopenharmony_ci    return ret;
100cabdff1aSopenharmony_ci}
101cabdff1aSopenharmony_ci
102cabdff1aSopenharmony_ciint main(int argc, char *argv[])
103cabdff1aSopenharmony_ci{
104cabdff1aSopenharmony_ci    int size, err;
105cabdff1aSopenharmony_ci    FILE *fin = NULL, *fout = NULL;
106cabdff1aSopenharmony_ci    AVFrame *sw_frame = NULL, *hw_frame = NULL;
107cabdff1aSopenharmony_ci    AVCodecContext *avctx = NULL;
108cabdff1aSopenharmony_ci    const AVCodec *codec = NULL;
109cabdff1aSopenharmony_ci    const char *enc_name = "h264_vaapi";
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_ci    if (argc < 5) {
112cabdff1aSopenharmony_ci        fprintf(stderr, "Usage: %s <width> <height> <input file> <output file>\n", argv[0]);
113cabdff1aSopenharmony_ci        return -1;
114cabdff1aSopenharmony_ci    }
115cabdff1aSopenharmony_ci
116cabdff1aSopenharmony_ci    width  = atoi(argv[1]);
117cabdff1aSopenharmony_ci    height = atoi(argv[2]);
118cabdff1aSopenharmony_ci    size   = width * height;
119cabdff1aSopenharmony_ci
120cabdff1aSopenharmony_ci    if (!(fin = fopen(argv[3], "r"))) {
121cabdff1aSopenharmony_ci        fprintf(stderr, "Fail to open input file : %s\n", strerror(errno));
122cabdff1aSopenharmony_ci        return -1;
123cabdff1aSopenharmony_ci    }
124cabdff1aSopenharmony_ci    if (!(fout = fopen(argv[4], "w+b"))) {
125cabdff1aSopenharmony_ci        fprintf(stderr, "Fail to open output file : %s\n", strerror(errno));
126cabdff1aSopenharmony_ci        err = -1;
127cabdff1aSopenharmony_ci        goto close;
128cabdff1aSopenharmony_ci    }
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_ci    err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI,
131cabdff1aSopenharmony_ci                                 NULL, NULL, 0);
132cabdff1aSopenharmony_ci    if (err < 0) {
133cabdff1aSopenharmony_ci        fprintf(stderr, "Failed to create a VAAPI device. Error code: %s\n", av_err2str(err));
134cabdff1aSopenharmony_ci        goto close;
135cabdff1aSopenharmony_ci    }
136cabdff1aSopenharmony_ci
137cabdff1aSopenharmony_ci    if (!(codec = avcodec_find_encoder_by_name(enc_name))) {
138cabdff1aSopenharmony_ci        fprintf(stderr, "Could not find encoder.\n");
139cabdff1aSopenharmony_ci        err = -1;
140cabdff1aSopenharmony_ci        goto close;
141cabdff1aSopenharmony_ci    }
142cabdff1aSopenharmony_ci
143cabdff1aSopenharmony_ci    if (!(avctx = avcodec_alloc_context3(codec))) {
144cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
145cabdff1aSopenharmony_ci        goto close;
146cabdff1aSopenharmony_ci    }
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    avctx->width     = width;
149cabdff1aSopenharmony_ci    avctx->height    = height;
150cabdff1aSopenharmony_ci    avctx->time_base = (AVRational){1, 25};
151cabdff1aSopenharmony_ci    avctx->framerate = (AVRational){25, 1};
152cabdff1aSopenharmony_ci    avctx->sample_aspect_ratio = (AVRational){1, 1};
153cabdff1aSopenharmony_ci    avctx->pix_fmt   = AV_PIX_FMT_VAAPI;
154cabdff1aSopenharmony_ci
155cabdff1aSopenharmony_ci    /* set hw_frames_ctx for encoder's AVCodecContext */
156cabdff1aSopenharmony_ci    if ((err = set_hwframe_ctx(avctx, hw_device_ctx)) < 0) {
157cabdff1aSopenharmony_ci        fprintf(stderr, "Failed to set hwframe context.\n");
158cabdff1aSopenharmony_ci        goto close;
159cabdff1aSopenharmony_ci    }
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci    if ((err = avcodec_open2(avctx, codec, NULL)) < 0) {
162cabdff1aSopenharmony_ci        fprintf(stderr, "Cannot open video encoder codec. Error code: %s\n", av_err2str(err));
163cabdff1aSopenharmony_ci        goto close;
164cabdff1aSopenharmony_ci    }
165cabdff1aSopenharmony_ci
166cabdff1aSopenharmony_ci    while (1) {
167cabdff1aSopenharmony_ci        if (!(sw_frame = av_frame_alloc())) {
168cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
169cabdff1aSopenharmony_ci            goto close;
170cabdff1aSopenharmony_ci        }
171cabdff1aSopenharmony_ci        /* read data into software frame, and transfer them into hw frame */
172cabdff1aSopenharmony_ci        sw_frame->width  = width;
173cabdff1aSopenharmony_ci        sw_frame->height = height;
174cabdff1aSopenharmony_ci        sw_frame->format = AV_PIX_FMT_NV12;
175cabdff1aSopenharmony_ci        if ((err = av_frame_get_buffer(sw_frame, 0)) < 0)
176cabdff1aSopenharmony_ci            goto close;
177cabdff1aSopenharmony_ci        if ((err = fread((uint8_t*)(sw_frame->data[0]), size, 1, fin)) <= 0)
178cabdff1aSopenharmony_ci            break;
179cabdff1aSopenharmony_ci        if ((err = fread((uint8_t*)(sw_frame->data[1]), size/2, 1, fin)) <= 0)
180cabdff1aSopenharmony_ci            break;
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ci        if (!(hw_frame = av_frame_alloc())) {
183cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
184cabdff1aSopenharmony_ci            goto close;
185cabdff1aSopenharmony_ci        }
186cabdff1aSopenharmony_ci        if ((err = av_hwframe_get_buffer(avctx->hw_frames_ctx, hw_frame, 0)) < 0) {
187cabdff1aSopenharmony_ci            fprintf(stderr, "Error code: %s.\n", av_err2str(err));
188cabdff1aSopenharmony_ci            goto close;
189cabdff1aSopenharmony_ci        }
190cabdff1aSopenharmony_ci        if (!hw_frame->hw_frames_ctx) {
191cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
192cabdff1aSopenharmony_ci            goto close;
193cabdff1aSopenharmony_ci        }
194cabdff1aSopenharmony_ci        if ((err = av_hwframe_transfer_data(hw_frame, sw_frame, 0)) < 0) {
195cabdff1aSopenharmony_ci            fprintf(stderr, "Error while transferring frame data to surface."
196cabdff1aSopenharmony_ci                    "Error code: %s.\n", av_err2str(err));
197cabdff1aSopenharmony_ci            goto close;
198cabdff1aSopenharmony_ci        }
199cabdff1aSopenharmony_ci
200cabdff1aSopenharmony_ci        if ((err = (encode_write(avctx, hw_frame, fout))) < 0) {
201cabdff1aSopenharmony_ci            fprintf(stderr, "Failed to encode.\n");
202cabdff1aSopenharmony_ci            goto close;
203cabdff1aSopenharmony_ci        }
204cabdff1aSopenharmony_ci        av_frame_free(&hw_frame);
205cabdff1aSopenharmony_ci        av_frame_free(&sw_frame);
206cabdff1aSopenharmony_ci    }
207cabdff1aSopenharmony_ci
208cabdff1aSopenharmony_ci    /* flush encoder */
209cabdff1aSopenharmony_ci    err = encode_write(avctx, NULL, fout);
210cabdff1aSopenharmony_ci    if (err == AVERROR_EOF)
211cabdff1aSopenharmony_ci        err = 0;
212cabdff1aSopenharmony_ci
213cabdff1aSopenharmony_ciclose:
214cabdff1aSopenharmony_ci    if (fin)
215cabdff1aSopenharmony_ci        fclose(fin);
216cabdff1aSopenharmony_ci    if (fout)
217cabdff1aSopenharmony_ci        fclose(fout);
218cabdff1aSopenharmony_ci    av_frame_free(&sw_frame);
219cabdff1aSopenharmony_ci    av_frame_free(&hw_frame);
220cabdff1aSopenharmony_ci    avcodec_free_context(&avctx);
221cabdff1aSopenharmony_ci    av_buffer_unref(&hw_device_ctx);
222cabdff1aSopenharmony_ci
223cabdff1aSopenharmony_ci    return err;
224cabdff1aSopenharmony_ci}
225