test_av_play.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /*
  2. * test_av_play.c - Test playing an MPEG A+V PES (e.g. VDR recordings) from a file.
  3. *
  4. * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
  5. * & Marcus Metzler <marcus@convergence.de>
  6. * for convergence integrated media GmbH
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. *
  22. * Thu Jun 24 09:18:44 CEST 2004
  23. * Add scan_file_av() and copy_to_dvb() for AV
  24. * filtering to be able to use AC3 audio streams
  25. * Copyright (C) 2004 Werner Fink <werner@suse.de>
  26. */
  27. #ifndef _GNU_SOURCE
  28. # define _GNU_SOURCE
  29. #endif
  30. #include <sys/ioctl.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #include <netinet/in.h>
  37. #include <fcntl.h>
  38. #include <time.h>
  39. #include <termios.h>
  40. #include <unistd.h>
  41. #include <errno.h>
  42. #include <linux/dvb/dmx.h>
  43. #include <linux/dvb/video.h>
  44. #include <linux/dvb/audio.h>
  45. #include <sys/poll.h>
  46. static char dolby;
  47. static char audio;
  48. static char black;
  49. static char volset;
  50. static int audioPlay(int fd)
  51. {
  52. int ans;
  53. if ((ans = ioctl(fd,AUDIO_PLAY)) < 0) {
  54. perror("AUDIO PLAY: ");
  55. return -1;
  56. }
  57. return 0;
  58. }
  59. static int audioSelectSource(int fd, audio_stream_source_t source)
  60. {
  61. int ans;
  62. if ((ans = ioctl(fd,AUDIO_SELECT_SOURCE, source)) < 0) {
  63. perror("AUDIO SELECT SOURCE: ");
  64. return -1;
  65. }
  66. return 0;
  67. }
  68. static int audioSetMute(int fd, int state)
  69. {
  70. int ans;
  71. if ((ans = ioctl(fd,AUDIO_SET_MUTE, state)) < 0) {
  72. perror("AUDIO SET MUTE: ");
  73. return -1;
  74. }
  75. return 0;
  76. }
  77. static int audioSetAVSync(int fd, int state)
  78. {
  79. int ans;
  80. if ((ans = ioctl(fd,AUDIO_SET_AV_SYNC, state)) < 0) {
  81. perror("AUDIO SET AV SYNC: ");
  82. return -1;
  83. }
  84. return 0;
  85. }
  86. static int audioSetVolume(int fd, int level)
  87. {
  88. int ans;
  89. audio_mixer_t mix;
  90. mix.volume_left = mix.volume_right = level;
  91. if ((ans = ioctl(fd, AUDIO_SET_MIXER, &mix)) < 0) {
  92. perror("AUDIO SET VOLUME: ");
  93. return -1;
  94. }
  95. return 0;
  96. }
  97. static int audioStop(int fd)
  98. {
  99. int ans;
  100. if ((ans = ioctl(fd,AUDIO_STOP,0)) < 0) {
  101. perror("AUDIO STOP: ");
  102. return -1;
  103. }
  104. return 0;
  105. }
  106. static int deviceClear(int afd, int vfd)
  107. {
  108. int ans;
  109. if (vfd >= 0) {
  110. if ((ans = ioctl(vfd, VIDEO_CLEAR_BUFFER, 0)) < 0) {
  111. perror("VIDEO CLEAR BUFFER: ");
  112. return -1;
  113. }
  114. }
  115. if (afd >= 0) {
  116. if ((ans = ioctl(afd, AUDIO_CLEAR_BUFFER, 0)) < 0) {
  117. perror("AUDIO CLEAR BUFFER: ");
  118. return -1;
  119. }
  120. }
  121. return 0;
  122. }
  123. static int videoStop(int fd)
  124. {
  125. int ans;
  126. if ((ans = ioctl(fd,VIDEO_STOP,0)) < 0) {
  127. perror("VIDEO STOP: ");
  128. return -1;
  129. }
  130. return 0;
  131. }
  132. static int videoPlay(int fd)
  133. {
  134. int ans;
  135. if ((ans = ioctl(fd,VIDEO_PLAY)) < 0) {
  136. perror("VIDEO PLAY: ");
  137. return -1;
  138. }
  139. return 0;
  140. }
  141. static int videoFreeze(int fd)
  142. {
  143. int ans;
  144. if ((ans = ioctl(fd,VIDEO_FREEZE)) < 0) {
  145. perror("VIDEO FREEZE: ");
  146. return -1;
  147. }
  148. return 0;
  149. }
  150. static int videoBlank(int fd, int state)
  151. {
  152. int ans;
  153. if ((ans = ioctl(fd, VIDEO_SET_BLANK, state)) < 0) {
  154. perror("VIDEO BLANK: ");
  155. return -1;
  156. }
  157. return 0;
  158. }
  159. static int videoContinue(int fd)
  160. {
  161. int ans;
  162. if ((ans = ioctl(fd,VIDEO_CONTINUE)) < 0) {
  163. perror("VIDEO CONTINUE: ");
  164. return -1;
  165. }
  166. return 0;
  167. }
  168. static int videoSelectSource(int fd, video_stream_source_t source)
  169. {
  170. int ans;
  171. if ((ans = ioctl(fd,VIDEO_SELECT_SOURCE, source)) < 0) {
  172. perror("VIDEO SELECT SOURCE: ");
  173. return -1;
  174. }
  175. return 0;
  176. }
  177. static int videoFastForward(int fd,int nframes)
  178. {
  179. int ans;
  180. if ((ans = ioctl(fd,VIDEO_FAST_FORWARD, nframes)) < 0) {
  181. perror("VIDEO FAST FORWARD: ");
  182. return -1;
  183. }
  184. return 0;
  185. }
  186. static int videoSlowMotion(int fd,int nframes)
  187. {
  188. int ans;
  189. if ((ans = ioctl(fd,VIDEO_SLOWMOTION, nframes)) < 0) {
  190. perror("VIDEO SLOWMOTION: ");
  191. return -1;
  192. }
  193. return 0;
  194. }
  195. #define NFD 3
  196. static void copy_to_dvb(int vfd, int afd, int cfd, const uint8_t* ptr, const unsigned short len)
  197. {
  198. struct pollfd pfd[NFD];
  199. unsigned short pos = 0;
  200. // int stopped = 0;
  201. pfd[0].fd = STDIN_FILENO;
  202. pfd[0].events = POLLIN;
  203. pfd[1].fd = vfd;
  204. pfd[1].events = POLLOUT;
  205. pfd[2].fd = afd;
  206. pfd[2].events = POLLOUT;
  207. while (pos < len) {
  208. int ret;
  209. if ((ret = poll(pfd,NFD,1)) > 0) {
  210. if (pfd[1].revents & POLLOUT) {
  211. int cnt = write(cfd, ptr + pos, len - pos);
  212. if (cnt > 0)
  213. pos += cnt;
  214. else if (cnt < 0) {
  215. if (errno != EAGAIN && errno != EINTR) {
  216. perror("Write:");
  217. exit(-1);
  218. }
  219. if (errno == EAGAIN)
  220. usleep(1000);
  221. continue;
  222. }
  223. }
  224. if (pfd[0].revents & POLLIN) {
  225. int c = getchar();
  226. switch(c) {
  227. case 'z':
  228. if (audio && !black) {
  229. audioSetMute(afd, 1);
  230. } else {
  231. videoFreeze(vfd);
  232. }
  233. deviceClear(afd, -1);
  234. printf("playback frozen\n");
  235. // stopped = 1;
  236. break;
  237. case 's':
  238. if (audio) {
  239. audioStop(afd);
  240. deviceClear(afd, -1);
  241. } else {
  242. videoStop(vfd);
  243. deviceClear(afd, vfd);
  244. }
  245. printf("playback stopped\n");
  246. // stopped = 1;
  247. break;
  248. case 'c':
  249. if (audio && !black) {
  250. audioSetAVSync(afd, 0);
  251. deviceClear(afd, -1);
  252. audioSetMute(afd, 0);
  253. } else {
  254. audioSetAVSync(afd, 1);
  255. deviceClear(afd, vfd);
  256. videoContinue(vfd);
  257. }
  258. printf("playback continued\n");
  259. // stopped = 0;
  260. break;
  261. case 'p':
  262. if (audio) {
  263. deviceClear(afd, -1);
  264. audioSetAVSync(afd, 0);
  265. audioPlay(afd);
  266. } else {
  267. deviceClear(afd, vfd);
  268. audioSetAVSync(afd, 1);
  269. audioPlay(afd);
  270. videoPlay(vfd);
  271. }
  272. audioSetMute(afd, 0);
  273. printf("playback started\n");
  274. // stopped = 0;
  275. break;
  276. case 'f':
  277. audioSetAVSync(afd, 0);
  278. if (!audio) {
  279. audioSetMute(afd, 1);
  280. videoFastForward(vfd,0);
  281. }
  282. printf("fastforward\n");
  283. // stopped = 0;
  284. break;
  285. case 'm':
  286. audioSetAVSync(afd, 0);
  287. audioSetMute(afd, 1);
  288. printf("mute\n");
  289. // stopped = 0;
  290. break;
  291. case 'u':
  292. audioSetAVSync(afd, 1);
  293. audioSetMute(afd, 0);
  294. printf("unmute\n");
  295. // stopped = 0;
  296. break;
  297. case 'd':
  298. if (dolby)
  299. dolby = 0;
  300. else
  301. dolby++;
  302. break;
  303. case 'l':
  304. audioSetAVSync(afd, 0);
  305. if (!audio) {
  306. audioSetMute(afd, 1);
  307. videoSlowMotion(vfd,2);
  308. }
  309. printf("slowmotion\n");
  310. // stopped = 0;
  311. break;
  312. case 'q':
  313. videoContinue(vfd);
  314. exit(0);
  315. break;
  316. default:
  317. break;
  318. }
  319. }
  320. } else if (ret < 0) {
  321. if (errno != EAGAIN && errno != EINTR) {
  322. perror("Write:");
  323. exit(-1);
  324. }
  325. if (errno == EAGAIN)
  326. usleep(1000);
  327. }
  328. }
  329. }
  330. static unsigned char play[6] = {0x00, 0x00, 0x01, 0xff, 0xff, 0xff};
  331. static unsigned char except[2];
  332. static int scan_file_av(int vfd, int afd, const unsigned char *buf, int buflen)
  333. {
  334. const unsigned char *const start = buf;
  335. const unsigned char *const end = buf + buflen;
  336. static unsigned int magic = 0xffffffff;
  337. static unsigned short count, len;
  338. static int fdc = -1;
  339. int m;
  340. while (buf < end) {
  341. if (count < 6) {
  342. switch (count) {
  343. case 0:
  344. m = 0;
  345. while ((magic & 0xffffff00) != 0x00000100) {
  346. if (buf >= end) goto out;
  347. magic = (magic << 8) | *buf++;
  348. m++;
  349. }
  350. if (m > 4)
  351. printf("Broken Frame found\n");
  352. play[3] = (unsigned char)(magic & 0x000000ff);
  353. switch (play[3]) {
  354. case 0xE0 ... 0xEF:
  355. fdc = vfd;
  356. if (except[0] != play[3]) {
  357. if (except[0] == 0)
  358. except[0] = play[3];
  359. else
  360. fdc = -1;
  361. }
  362. if (audio)
  363. fdc = -1;
  364. break;
  365. case 0xC0 ... 0xDF:
  366. fdc = afd;
  367. if (dolby) {
  368. fdc = -1;
  369. break;
  370. }
  371. if (except[1] != play[3]) {
  372. if (except[1] == 0)
  373. except[1] = play[3];
  374. else
  375. fdc = -1;
  376. }
  377. if (!volset) {
  378. audioSetVolume(afd, 255);
  379. volset = 1;
  380. }
  381. break;
  382. case 0xBD:
  383. /*
  384. * TODO: sub filter to through out e.g. ub pictures
  385. * in Private Streams 1 _and_ get sub audio header
  386. * to set an except(ion) audio stream.
  387. * The later one requires some changes within the VDR
  388. * remux part! 2004/07/01 Werner
  389. */
  390. fdc = afd;
  391. if (!dolby) {
  392. fdc = -1;
  393. break;
  394. }
  395. if (volset) {
  396. audioSetVolume(afd, 0);
  397. volset = 0;
  398. }
  399. break;
  400. default:
  401. fdc = -1;
  402. break;
  403. }
  404. count = 4;
  405. case 4:
  406. if (buf >= end) goto out;
  407. len = ((*buf) << 8);
  408. play[4] = (*buf);
  409. buf++;
  410. count++;
  411. case 5:
  412. if (buf >= end) goto out;
  413. len |= (*buf);
  414. len += 6;
  415. play[5] = (*buf);
  416. buf++;
  417. count++;
  418. if (fdc != -1)
  419. copy_to_dvb(vfd, afd, fdc, &play[0], count);
  420. default:
  421. break;
  422. }
  423. }
  424. while (count < len) {
  425. int rest = end - buf;
  426. if (rest <= 0) goto out;
  427. if (rest + count > len)
  428. rest = len - count;
  429. if (fdc != -1)
  430. copy_to_dvb(vfd, afd, fdc, buf, rest);
  431. count += rest;
  432. buf += rest;
  433. }
  434. /* Reset for next scan */
  435. magic = 0xffffffff;
  436. count = len = 0;
  437. fdc = -1;
  438. play[3] = 0xff;
  439. }
  440. out:
  441. return buf - start;
  442. }
  443. #define BUFFY 32768
  444. static void play_file_av(int filefd, int vfd, int afd)
  445. {
  446. unsigned char buf[BUFFY];
  447. int count;
  448. audioSetMute(afd, 1);
  449. videoBlank(vfd, 1);
  450. if (audio && !black) {
  451. audioStop(afd);
  452. deviceClear(afd, -1);
  453. audioSetAVSync(afd, 0);
  454. audioSelectSource(afd, AUDIO_SOURCE_MEMORY);
  455. audioPlay(afd);
  456. videoBlank(vfd, 0);
  457. } else if (audio && black) {
  458. deviceClear(afd, vfd);
  459. videoBlank(vfd, 1);
  460. audioSetAVSync(afd, 0);
  461. audioSelectSource(afd, AUDIO_SOURCE_MEMORY);
  462. videoSelectSource(vfd, VIDEO_SOURCE_MEMORY);
  463. audioPlay(afd);
  464. videoPlay(vfd);
  465. } else {
  466. deviceClear(afd, vfd);
  467. audioSetAVSync(afd, 1);
  468. audioSelectSource(afd, AUDIO_SOURCE_MEMORY);
  469. videoSelectSource(vfd, VIDEO_SOURCE_MEMORY);
  470. audioPlay(afd);
  471. videoPlay(vfd);
  472. videoBlank(vfd, 0);
  473. }
  474. if (dolby) {
  475. audioSetVolume(afd, 0);
  476. volset = 0;
  477. } else {
  478. audioSetVolume(afd, 255);
  479. volset = 1;
  480. }
  481. #ifndef __stub_posix_fadvise
  482. posix_fadvise(filefd, 0, 0, POSIX_FADV_SEQUENTIAL);
  483. #endif
  484. while ((count = read(filefd,buf,BUFFY)) > 0)
  485. scan_file_av(vfd,afd,buf,count);
  486. }
  487. static struct termios term;
  488. static void restore(void)
  489. {
  490. tcsetattr(STDIN_FILENO, TCSANOW, &term);
  491. }
  492. int main(int argc, char **argv)
  493. {
  494. int vfd, afd, c;
  495. int filefd;
  496. const char *videodev = "/dev/dvb/adapter0/video0";
  497. const char *audiodev = "/dev/dvb/adapter0/audio0";
  498. if (((tcgetpgrp(STDIN_FILENO) == getpid()) || (getppid() != (pid_t)1))
  499. && (tcgetattr(STDIN_FILENO, &term) == 0)) {
  500. struct termios newterm;
  501. memcpy(&newterm, &term, sizeof(struct termios));
  502. newterm.c_iflag = 0;
  503. newterm.c_lflag &= ~(ICANON | ECHO);
  504. newterm.c_cc[VMIN] = 0;
  505. newterm.c_cc[VTIME] = 0;
  506. atexit(restore);
  507. tcsetattr(STDIN_FILENO, TCSANOW, &newterm);
  508. }
  509. opterr = 0;
  510. while ((c = getopt(argc, argv, "+daA")) != -1) {
  511. switch (c) {
  512. case 'd':
  513. dolby++;
  514. break;
  515. case 'a':
  516. audio++;
  517. break;
  518. case 'A':
  519. audio++;
  520. black++;
  521. break;
  522. case '?':
  523. fprintf(stderr, "usage: test_av_play [-d] [-a] [-A] mpeg_A+V_PES_file\n");
  524. return 1;
  525. default:
  526. break;
  527. }
  528. }
  529. argv += optind;
  530. argc -= optind;
  531. if (getenv("VIDEO"))
  532. videodev = getenv("VIDEO");
  533. if (getenv("AUDIO"))
  534. audiodev = getenv("AUDIO");
  535. printf("using video device '%s'\n", videodev);
  536. printf("using audio device '%s'\n", audiodev);
  537. putchar('\n');
  538. printf("Freeze by pressing `z'\n");
  539. printf("Stop by pressing `s'\n");
  540. printf("Continue by pressing `c'\n");
  541. printf("Start by pressing `p'\n");
  542. printf("FastForward by pressing `f'\n");
  543. printf("Mute by pressing `m'\n");
  544. printf("UnMute by pressing `u'\n");
  545. printf("MP2/AC3 by pressing `d'\n");
  546. printf("SlowMotion by pressing `l'\n");
  547. printf("Quit by pressing `q'\n");
  548. putchar('\n');
  549. errno = ENOENT;
  550. if (!argv[0] || (filefd = open(argv[0], O_RDONLY)) < 0) {
  551. perror("File open:");
  552. return -1;
  553. }
  554. if ((vfd = open(videodev,O_RDWR|O_NONBLOCK)) < 0) {
  555. perror("VIDEO DEVICE: ");
  556. return -1;
  557. }
  558. if ((afd = open(audiodev,O_RDWR|O_NONBLOCK)) < 0) {
  559. perror("AUDIO DEVICE: ");
  560. return -1;
  561. }
  562. play_file_av(filefd, vfd, afd);
  563. close(vfd);
  564. close(afd);
  565. close(filefd);
  566. return 0;
  567. }