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