1 /*
2 * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16 /**************************************************
17 * example based on amcodec
18 **************************************************/
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <errno.h>
29 #include <stdbool.h>
30 #include <ctype.h>
31 #include <codec.h>
32 #include <amvideo.h>
33 #include <IONmem.h>
34
35 #define READ_SIZE (64 * 1024)
36 #define EXTERNAL_PTS (1)
37 #define SYNC_OUTSIDE (2)
38 #define UNIT_FREQ 96000
39 #define PTS_FREQ 90000
40 #define AV_SYNC_THRESH PTS_FREQ*30
41 #define MESON_BUFFER_SIZE 4
42
43 static codec_para_t v_codec_para;
44 static codec_para_t *vpcodec;
45 #ifdef AUDIO_ES
46 static codec_para_t a_codec_para;
47 static codec_para_t *apcodec;
48 #endif
49 static codec_para_t *pcodec;
50 static char *filename;
51 FILE* fp = NULL;
52 FILE* yuv = NULL;
53 static int axis[8] = {0};
54 struct amvideo_dev *amvideo;
55
56 struct out_buffer_t {
57 int index;
58 int size;
59 bool own_by_v4l;
60 void *ptr;
61 IONMEM_AllocParams buffer;
62 } vbuffer[MESON_BUFFER_SIZE];
63
amsysfs_set_sysfs_str(const char * path,const char * val)64 static int amsysfs_set_sysfs_str(const char *path, const char *val)
65 {
66 int fd;
67 int bytes;
68 fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
69 if (fd >= 0) {
70 bytes = write(fd, val, strlen(val));
71 close(fd);
72 return 0;
73 } else {
74 printf("unable to open file %s,err: %s\n", path, strerror(errno));
75 }
76 return -1;
77 }
78
osd_blank(char * path,int cmd)79 int osd_blank(char *path, int cmd)
80 {
81 int fd;
82 char bcmd[16];
83 fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
84
85 if (fd >= 0) {
86 sprintf(bcmd, "%d", cmd);
87 write(fd, bcmd, strlen(bcmd));
88 close(fd);
89 return 0;
90 }
91
92 return -1;
93 }
94
set_tsync_enable(int enable)95 int set_tsync_enable(int enable)
96 {
97 int fd;
98 char *path = "/sys/class/tsync/enable";
99 char bcmd[16];
100 fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
101 if (fd >= 0) {
102 sprintf(bcmd, "%d", enable);
103 write(fd, bcmd, strlen(bcmd));
104 close(fd);
105 return 0;
106 }
107
108 return -1;
109 }
110
parse_para(const char * para,int para_num,int * result)111 int parse_para(const char *para, int para_num, int *result)
112 {
113 char *endp;
114 const char *startp = para;
115 int *out = result;
116 int len = 0, count = 0;
117
118 if (!startp) {
119 return 0;
120 }
121
122 len = strlen(startp);
123
124 do {
125 //filter space out
126 while (startp && (isspace(*startp) || !isgraph(*startp)) && len) {
127 startp++;
128 len--;
129 }
130
131 if (len == 0) {
132 break;
133 }
134
135 *out++ = strtol(startp, &endp, 0);
136
137 len -= endp - startp;
138 startp = endp;
139 count++;
140
141 } while ((endp) && (count < para_num) && (len > 0));
142
143 return count;
144 }
145
set_display_axis(int recovery)146 int set_display_axis(int recovery)
147 {
148 int fd;
149 char *path = "/sys/class/display/axis";
150 char str[128];
151 int count;
152 fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
153 if (fd >= 0) {
154 if (!recovery) {
155 read(fd, str, 128);
156 printf("read axis %s, length %d\n", str, strlen(str));
157 count = parse_para(str, 8, axis);
158 }
159 if (recovery) {
160 sprintf(str, "%d %d %d %d %d %d %d %d",
161 axis[0], axis[1], axis[2], axis[3], axis[4], axis[5], axis[6], axis[7]);
162 } else {
163 sprintf(str, "2048 %d %d %d %d %d %d %d",
164 axis[1], axis[2], axis[3], axis[4], axis[5], axis[6], axis[7]);
165 }
166 write(fd, str, strlen(str));
167 close(fd);
168 return 0;
169 }
170
171 return -1;
172 }
FreeBuffers()173 static void FreeBuffers()
174 {
175 int i;
176 for (i = 0; i < MESON_BUFFER_SIZE; i++) {
177 if (vbuffer[i].ptr) {
178 CMEM_free(&vbuffer[i].buffer);
179 }
180 }
181 }
AllocBuffers(int width,int height)182 static int AllocBuffers(int width, int height)
183 {
184 int i, size, ret;
185 CMEM_init();
186 size = width * height * 3 / 2;
187 for (i = 0; i < MESON_BUFFER_SIZE; i++) {
188 ret = CMEM_alloc(size, &vbuffer[i].buffer);
189 if (ret < 0) {
190 printf("CMEM_alloc failed\n");
191 FreeBuffers();
192 goto fail;
193 }
194 vbuffer[i].index = i;
195 vbuffer[i].size = size;
196 vbuffer[i].ptr = vbuffer[i].buffer.vaddr;
197 }
198 fail:
199 return ret;
200 }
ionvideo_init(int width,int height)201 static int ionvideo_init(int width, int height)
202 {
203 int i, ret;
204
205
206 amsysfs_set_sysfs_str("/sys/class/vfm/map", "rm default");
207 amsysfs_set_sysfs_str("/sys/class/vfm/map",
208 "add default decoder ionvideo");
209
210 ret = AllocBuffers(width, height);
211 if (ret < 0) {
212 printf("AllocBuffers failed\n");
213 ret = -ENODEV;
214 goto fail;
215 }
216
217 amvideo = new_amvideo(FLAGS_V4L_MODE);
218 if (!amvideo) {
219 printf("amvideo create failed\n");
220 ret = -ENODEV;
221 goto fail;
222 }
223 amvideo->display_mode = 0;
224 amvideo->use_frame_mode = 0;
225
226 ret = amvideo_init(amvideo, 0, width, height,
227 V4L2_PIX_FMT_NV12, MESON_BUFFER_SIZE);
228 if (ret < 0) {
229 printf("amvideo_init failed\n");
230 amvideo_release(amvideo);
231 goto fail;
232 }
233 ret = amvideo_start(amvideo);
234 if (ret < 0) {
235 amvideo_release(amvideo);
236 goto fail;
237 }
238 for (i = 0; i < MESON_BUFFER_SIZE; i++) {
239 vframebuf_t vf;
240 vf.fd = vbuffer[i].buffer.mIonHnd;
241 vf.length = vbuffer[i].buffer.size;
242 vf.index = vbuffer[i].index;
243 ret = amlv4l_queuebuf(amvideo, &vf);
244 }
245 fail:
246 return ret;
247 }
248
ionvideo_close()249 static void ionvideo_close()
250 {
251 amvideo_stop(amvideo);
252 amvideo_release(amvideo);
253 }
254
signal_handler(int signum)255 static void signal_handler(int signum)
256 {
257 printf("Get signum=%x\n", signum);
258 #ifdef AUDIO_ES
259 codec_close(apcodec);
260 #endif
261 codec_close(vpcodec);
262 fclose(fp);
263 set_display_axis(1);
264 signal(signum, SIG_DFL);
265 raise(signum);
266 ionvideo_close();
267 FreeBuffers();
268 }
269
main(int argc,char * argv[])270 int main(int argc, char *argv[])
271 {
272 int ret = CODEC_ERROR_NONE;
273 char buffer[READ_SIZE];
274
275 uint32_t Readlen;
276 uint32_t isize;
277 struct buf_status vbuf;
278
279 if (argc < 6) {
280 printf("Corret command: ionplayer <filename> <width> <height> <fps> <format(1:mpeg4 2:h264)> [subformat for mpeg4]\n");
281 return -1;
282 }
283 #if 0
284 if (osd_blank("/sys/class/graphics/fb0/blank", 1) < 0)
285 osd_blank("/sys/kernel/debug/dri/0/vpu/blank", 1);
286 if (osd_blank("/sys/class/graphics/fb1/blank", 0) < 0)
287 osd_blank("/sys/kernel/debug/dri/64/vpu/blank", 1);
288 #endif
289 set_display_axis(0);
290 #ifdef AUDIO_ES
291 apcodec = &a_codec_para;
292 memset(apcodec, 0, sizeof(codec_para_t));
293 #endif
294
295 vpcodec = &v_codec_para;
296 memset(vpcodec, 0, sizeof(codec_para_t));
297
298 vpcodec->has_video = 1;
299 vpcodec->video_type = atoi(argv[5]);
300 if (vpcodec->video_type == VFORMAT_H264) {
301 vpcodec->am_sysinfo.format = VIDEO_DEC_FORMAT_H264;
302 vpcodec->am_sysinfo.param = (void *)(EXTERNAL_PTS | SYNC_OUTSIDE);
303 } else if (vpcodec->video_type == VFORMAT_MPEG4) {
304 if (argc < 7) {
305 printf("No subformat for mpeg4, take the default VIDEO_DEC_FORMAT_MPEG4_5\n");
306 vpcodec->am_sysinfo.format = VIDEO_DEC_FORMAT_MPEG4_5;
307 } else {
308 vpcodec->am_sysinfo.format = atoi(argv[6]);
309 }
310 }
311
312 vpcodec->stream_type = STREAM_TYPE_ES_VIDEO;
313 vpcodec->am_sysinfo.rate = 96000 / atoi(argv[4]);
314 vpcodec->am_sysinfo.height = atoi(argv[3]);
315 vpcodec->am_sysinfo.width = atoi(argv[2]);
316 vpcodec->has_audio = 0;
317 vpcodec->noblock = 0;
318
319 #ifdef AUDIO_ES
320 apcodec->audio_type = AFORMAT_MPEG;
321 apcodec->stream_type = STREAM_TYPE_ES_AUDIO;
322 apcodec->audio_pid = 0x1023;
323 apcodec->has_audio = 1;
324 apcodec->audio_channels = 2;
325 apcodec->audio_samplerate = 48000;
326 apcodec->noblock = 0;
327 apcodec->audio_info.channels = 2;
328 apcodec->audio_info.sample_rate = 48000;
329 #endif
330
331 printf("\n*********CODEC PLAYER DEMO************\n\n");
332 filename = argv[1];
333 printf("file %s to be played\n", filename);
334
335 if ((fp = fopen(filename, "rb")) == NULL) {
336 printf("open file error!\n");
337 return -1;
338 }
339
340 if ((yuv = fopen("./yuv.yuv", "wb")) == NULL) {
341 printf("./yuv.yuv dump open file error!\n");
342 return -1;
343 }
344
345 ionvideo_init(vpcodec->am_sysinfo.width, vpcodec->am_sysinfo.height);
346 #ifdef AUDIO_ES
347 ret = codec_init(apcodec);
348 if (ret != CODEC_ERROR_NONE) {
349 printf("codec init failed, ret=-0x%x", -ret);
350 return -1;
351 }
352 #endif
353
354 ret = codec_init(vpcodec);
355 if (ret != CODEC_ERROR_NONE) {
356 printf("codec init failed, ret=-0x%x", -ret);
357 return -1;
358 }
359 printf("video codec ok!\n");
360
361 //codec_set_cntl_avthresh(vpcodec, AV_SYNC_THRESH);
362 //codec_set_cntl_syncthresh(vpcodec, 0);
363
364 set_tsync_enable(0);
365
366 pcodec = vpcodec;
367 while (!feof(fp)) {
368 Readlen = fread(buffer, 1, READ_SIZE, fp);
369 printf("Readlen %d\n", Readlen);
370 if (Readlen <= 0) {
371 printf("read file error!\n");
372 rewind(fp);
373 }
374
375 isize = 0;
376 do {
377 vframebuf_t vf;
378 ret = amlv4l_dequeuebuf(amvideo, &vf);
379 if (ret >= 0) {
380 printf("vf idx%d pts 0x%llx\n", vf.index, vf.pts);
381 fwrite(vbuffer[vf.index].ptr, vbuffer[vf.index].size, 1, yuv);
382 fflush(yuv);
383 ret = amlv4l_queuebuf(amvideo, &vf);
384 if (ret < 0) {
385 printf("amlv4l_queuebuf %d\n", ret);
386 }
387 } else {
388 printf("amlv4l_dequeuebuf %d\n", ret);
389 }
390 ret = codec_write(pcodec, buffer + isize, Readlen);
391 if (ret < 0) {
392 if (errno != EAGAIN) {
393 printf("write data failed, errno %d\n", errno);
394 goto error;
395 } else {
396 continue;
397 }
398 } else {
399 isize += ret;
400 }
401
402 printf("ret %d, isize %d\n", ret, isize);
403 } while (isize < Readlen);
404
405 signal(SIGCHLD, SIG_IGN);
406 signal(SIGTSTP, SIG_IGN);
407 signal(SIGTTOU, SIG_IGN);
408 signal(SIGTTIN, SIG_IGN);
409 signal(SIGHUP, signal_handler);
410 signal(SIGTERM, signal_handler);
411 signal(SIGSEGV, signal_handler);
412 signal(SIGINT, signal_handler);
413 signal(SIGQUIT, signal_handler);
414 }
415
416 do {
417 vframebuf_t vf;
418 ret = codec_get_vbuf_state(pcodec, &vbuf);
419 if (ret != 0) {
420 printf("codec_get_vbuf_state error: %x\n", -ret);
421 goto error;
422 }
423
424 ret = amlv4l_dequeuebuf(amvideo, &vf);
425 if (ret >= 0) {
426 printf("vf idx%d pts 0x%llx\n", vf.index, vf.pts);
427 fwrite(vbuffer[vf.index].ptr, vbuffer[vf.index].size, 1, yuv);
428 fflush(yuv);
429 ret = amlv4l_queuebuf(amvideo, &vf);
430 if (ret < 0) {
431 //printf("amlv4l_queuebuf %d\n", ret);
432 }
433 } else {
434 //printf("amlv4l_dequeuebuf %d\n", ret);
435 }
436 } while (vbuf.data_len > 0x100);
437
438 error:
439 #ifdef AUDIO_ES
440 codec_close(apcodec);
441 #endif
442 codec_close(vpcodec);
443 fclose(fp);
444 fclose(yuv);
445 set_display_axis(1);
446 ionvideo_close();
447 FreeBuffers();
448 return 0;
449 }
450
451