ffmpeg+sdl教程----编写一个简单的播放器6(其他的时钟同步方式)

来源:http://blog.csdn.net/mu399/article/details/5818384

在理解上一个教程的基础上,这篇教程就稍微容易理解些了,不外乎多加了两种同步方式,同步音频到视频,同步音频视频到外部时钟。

这篇教程主要是新增了不少新变量,is->video_current_pts用于保存当前视频帧的时间戳(以秒为单位),只在 video_refresh_timer函数中播放一帧视频前改变,is->video_current_pts_time单位为毫秒,在 stream_component_open中初始化,也在video_refresh_timer函数中初始化。

这篇教程的难点是对synchronize_audio函数的理解,它的功能是测量声音的位置,把它与参考时间进行比较,然后算出我们需要修正多少的样本 数,也就是说:我们是否需要通过丢弃样本的方式来加速播放还是需要通过插值样本的方式来放慢播放,这个函数在教程中有详细的说明。

[cpp] view plaincopy

  1. // tutorial05.c
  2. // A pedagogical video player that really works!
  3. //
  4. // Code based on FFplay, Copyright (c) 2003 Fabrice Bellard,
  5. // and a tutorial by Martin Bohme ([email protected])
  6. // Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
  7. // Use
  8. //
  9. // gcc -o tutorial05 tutorial05.c -lavformat -lavcodec -lz -lm `sdl-config --cflags --libs`
  10. // to build (assuming libavformat and libavcodec are correctly installed,
  11. // and assuming you have sdl-config. Please refer to SDL docs for your installation.)
  12. //
  13. // Run using
  14. // tutorial05 myvideofile.mpg
  15. //
  16. // to play the video.
  17. #include "libavformat/avformat.h"
  18. #include "libswscale/swscale.h"
  19. #include <SDL/SDL.h>
  20. #include <SDL/SDL_thread.h>
  21. #ifdef main
  22. #undef main /* Prevents SDL from overriding main() */
  23. #endif
  24. #include <stdio.h>
  25. #include <math.h>
  26. #define SDL_AUDIO_BUFFER_SIZE 1024
  27. #define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
  28. #define MAX_VIDEOQ_SIZE (5 * 256 * 1024)
  29. #define AV_SYNC_THRESHOLD 0.01
  30. #define AV_NOSYNC_THRESHOLD 10.0
  31. #define SAMPLE_CORRECTION_PERCENT_MAX 10
  32. #define AUDIO_DIFF_AVG_NB 20
  33. #define FF_ALLOC_EVENT   (SDL_USEREVENT)
  34. #define FF_REFRESH_EVENT (SDL_USEREVENT + 1)
  35. #define FF_QUIT_EVENT (SDL_USEREVENT + 2)
  36. #define VIDEO_PICTURE_QUEUE_SIZE 1
  37. #define DEFAULT_AV_SYNC_TYPE AV_SYNC_EXTERNAL_MASTER
  38. enum
  39. {
  40. AV_SYNC_AUDIO_MASTER,
  41. AV_SYNC_VIDEO_MASTER,
  42. AV_SYNC_EXTERNAL_MASTER,
  43. };
  44. typedef struct PacketQueue
  45. {
  46. AVPacketList *first_pkt, *last_pkt;
  47. int nb_packets;
  48. int size;
  49. SDL_mutex *mutex;
  50. SDL_cond *cond;
  51. } PacketQueue;
  52. typedef struct VideoPicture
  53. {
  54. SDL_Overlay *bmp;
  55. int width, height; /* source height & width */
  56. int allocated;
  57. double pts;
  58. } VideoPicture;
  59. typedef struct VideoState
  60. {
  61. AVFormatContext *pFormatCtx;
  62. int             videoStream, audioStream;
  63. int             av_sync_type;
  64. double          audio_clock;
  65. AVStream        *audio_st;
  66. PacketQueue     audioq;
  67. uint8_t         audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
  68. unsigned int    audio_buf_size;
  69. unsigned int    audio_buf_index;
  70. AVPacket        audio_pkt;
  71. uint8_t         *audio_pkt_data;
  72. int             audio_pkt_size;
  73. int             audio_hw_buf_size;
  74. double          audio_diff_cum; /* used for AV difference average computation */
  75. double          audio_diff_avg_coef;
  76. double          audio_diff_threshold;
  77. int             audio_diff_avg_count;
  78. double          frame_timer;
  79. double          frame_last_pts;
  80. double          frame_last_delay;
  81. double          video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame
  82. double          video_current_pts; ///<current displayed pts (different from video_clock if frame fifos are used)
  83. int64_t         video_current_pts_time;  ///<time (av_gettime) at which we updated video_current_pts - used to have running video pts
  84. AVStream        *video_st;
  85. PacketQueue     videoq;
  86. VideoPicture    pictq[VIDEO_PICTURE_QUEUE_SIZE];
  87. int             pictq_size, pictq_rindex, pictq_windex;
  88. SDL_mutex       *pictq_mutex;
  89. SDL_cond        *pictq_cond;
  90. SDL_Thread      *parse_tid;
  91. SDL_Thread      *video_tid;
  92. char            filename[1024];
  93. int             quit;
  94. } VideoState;
  95. SDL_Surface     *screen;
  96. /* Since we only have one decoding thread, the Big Struct
  97. can be global in case we need it. */
  98. VideoState *global_video_state;
  99. void packet_queue_init(PacketQueue *q)
  100. {
  101. memset(q, 0, sizeof(PacketQueue));
  102. q->mutex = SDL_CreateMutex();
  103. q->cond = SDL_CreateCond();
  104. }
  105. int packet_queue_put(PacketQueue *q, AVPacket *pkt)
  106. {
  107. AVPacketList *pkt1;
  108. if(av_dup_packet(pkt) < 0)
  109. {
  110. return -1;
  111. }
  112. pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList));
  113. if (!pkt1)
  114. return -1;
  115. pkt1->pkt = *pkt;
  116. pkt1->next = NULL;
  117. SDL_LockMutex(q->mutex);
  118. if (!q->last_pkt)
  119. q->first_pkt = pkt1;
  120. else
  121. q->last_pkt->next = pkt1;
  122. q->last_pkt = pkt1;
  123. q->nb_packets++;
  124. q->size += pkt1->pkt.size;
  125. SDL_CondSignal(q->cond);
  126. SDL_UnlockMutex(q->mutex);
  127. return 0;
  128. }
  129. static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
  130. {
  131. AVPacketList *pkt1;
  132. int ret;
  133. SDL_LockMutex(q->mutex);
  134. for(;;)
  135. {
  136. if(global_video_state->quit)
  137. {
  138. ret = -1;
  139. break;
  140. }
  141. pkt1 = q->first_pkt;
  142. if (pkt1)
  143. {
  144. q->first_pkt = pkt1->next;
  145. if (!q->first_pkt)
  146. q->last_pkt = NULL;
  147. q->nb_packets--;
  148. q->size -= pkt1->pkt.size;
  149. *pkt = pkt1->pkt;
  150. av_free(pkt1);
  151. ret = 1;
  152. break;
  153. }
  154. else if (!block)
  155. {
  156. ret = 0;
  157. break;
  158. }
  159. else
  160. {
  161. SDL_CondWait(q->cond, q->mutex);
  162. }
  163. }
  164. SDL_UnlockMutex(q->mutex);
  165. return ret;
  166. }
  167. double get_audio_clock(VideoState *is)
  168. {
  169. double pts;
  170. int hw_buf_size, bytes_per_sec, n;
  171. pts = is->audio_clock; /* maintained in the audio thread */
  172. hw_buf_size = is->audio_buf_size - is->audio_buf_index;
  173. bytes_per_sec = 0;
  174. n = is->audio_st->codec->channels * 2;
  175. if(is->audio_st)
  176. {
  177. bytes_per_sec = is->audio_st->codec->sample_rate * n;
  178. }
  179. if(bytes_per_sec)
  180. {
  181. pts -= (double)hw_buf_size / bytes_per_sec;
  182. }
  183. return pts;
  184. }
  185. double get_video_clock(VideoState *is)
  186. {
  187. double delta;
  188. delta = (av_gettime() - is->video_current_pts_time) / 1000000.0;
  189. return is->video_current_pts + delta;
  190. }
  191. double get_external_clock(VideoState *is)
  192. {
  193. return av_gettime() / 1000000.0;
  194. }
  195. double get_master_clock(VideoState *is)
  196. {
  197. if(is->av_sync_type == AV_SYNC_VIDEO_MASTER)
  198. {
  199. return get_video_clock(is);
  200. }
  201. else if(is->av_sync_type == AV_SYNC_AUDIO_MASTER)
  202. {
  203. return get_audio_clock(is);
  204. }
  205. else
  206. {
  207. return get_external_clock(is);
  208. }
  209. }
  210. /* Add or subtract samples to get a better sync, return new
  211. audio buffer size */
  212. int synchronize_audio(VideoState *is, short *samples,int samples_size, double pts)
  213. {
  214. int n;
  215. double ref_clock;
  216. n = 2 * is->audio_st->codec->channels;
  217. if(is->av_sync_type != AV_SYNC_AUDIO_MASTER)
  218. {
  219. double diff, avg_diff;
  220. int wanted_size, min_size, max_size, nb_samples;
  221. ref_clock = get_master_clock(is);
  222. diff = get_audio_clock(is) - ref_clock;
  223. if(diff < AV_NOSYNC_THRESHOLD)
  224. {
  225. // accumulate the diffs
  226. is->audio_diff_cum = diff + is->audio_diff_avg_coef
  227. * is->audio_diff_cum;
  228. if(is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB)
  229. {
  230. is->audio_diff_avg_count++;
  231. }
  232. else
  233. {
  234. avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
  235. if(fabs(avg_diff) >= is->audio_diff_threshold)
  236. {
  237. wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n);
  238. min_size = samples_size * ((100 - SAMPLE_CORRECTION_PERCENT_MAX) / 100);
  239. max_size = samples_size * ((100 + SAMPLE_CORRECTION_PERCENT_MAX) / 100);
  240. if(wanted_size < min_size)
  241. {
  242. wanted_size = min_size;
  243. }
  244. else if (wanted_size > max_size)
  245. {
  246. wanted_size = max_size;
  247. }
  248. if(wanted_size < samples_size)
  249. {
  250. /* remove samples */
  251. samples_size = wanted_size;
  252. }
  253. else if(wanted_size > samples_size)
  254. {
  255. uint8_t *samples_end, *q;
  256. int nb;
  257. /* add samples by copying final sample*/
  258. nb = (samples_size - wanted_size);
  259. samples_end = (uint8_t *)samples + samples_size - n;
  260. q = samples_end + n;
  261. while(nb > 0)
  262. {
  263. memcpy(q, samples_end, n);
  264. q += n;
  265. nb -= n;
  266. }
  267. samples_size = wanted_size;
  268. }
  269. }
  270. }
  271. }
  272. else
  273. {
  274. /* difference is TOO big; reset diff stuff */
  275. is->audio_diff_avg_count = 0;
  276. is->audio_diff_cum = 0;
  277. }
  278. }
  279. return samples_size;
  280. }
  281. int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size, double *pts_ptr)
  282. {
  283. int len1, data_size, n;
  284. AVPacket *pkt = &is->audio_pkt;
  285. double pts;
  286. for(;;)
  287. {
  288. while(is->audio_pkt_size > 0)
  289. {
  290. data_size = buf_size;
  291. len1 = avcodec_decode_audio2(is->audio_st->codec,
  292. (int16_t *)audio_buf, &data_size,
  293. is->audio_pkt_data, is->audio_pkt_size);
  294. if(len1 < 0)
  295. {
  296. /* if error, skip frame */
  297. is->audio_pkt_size = 0;
  298. break;
  299. }
  300. is->audio_pkt_data += len1;
  301. is->audio_pkt_size -= len1;
  302. if(data_size <= 0)
  303. {
  304. /* No data yet, get more frames */
  305. continue;
  306. }
  307. pts = is->audio_clock;
  308. *pts_ptr = pts;
  309. n = 2 * is->audio_st->codec->channels;
  310. is->audio_clock += (double)data_size /
  311. (double)(n * is->audio_st->codec->sample_rate);
  312. /* We have data, return it and come back for more later */
  313. return data_size;
  314. }
  315. if(pkt->data)
  316. av_free_packet(pkt);
  317. if(is->quit)
  318. {
  319. return -1;
  320. }
  321. /* next packet */
  322. if(packet_queue_get(&is->audioq, pkt, 1) < 0)
  323. {
  324. return -1;
  325. }
  326. is->audio_pkt_data = pkt->data;
  327. is->audio_pkt_size = pkt->size;
  328. /* if update, update the audio clock w/pts */
  329. if(pkt->pts != AV_NOPTS_VALUE)
  330. {
  331. is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
  332. }
  333. }
  334. }
  335. void audio_callback(void *userdata, Uint8 *stream, int len)
  336. {
  337. VideoState *is = (VideoState *)userdata;
  338. int len1, audio_size;
  339. double pts;
  340. while(len > 0)
  341. {
  342. if(is->audio_buf_index >= is->audio_buf_size)
  343. {
  344. /* We have already sent all our data; get more */
  345. audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts);
  346. if(audio_size < 0)
  347. {
  348. /* If error, output silence */
  349. is->audio_buf_size = 1024;
  350. memset(is->audio_buf, 0, is->audio_buf_size);
  351. }
  352. else
  353. {
  354. audio_size = synchronize_audio(is, (int16_t *)is->audio_buf,audio_size, pts);
  355. is->audio_buf_size = audio_size;
  356. }
  357. is->audio_buf_index = 0;
  358. }
  359. len1 = is->audio_buf_size - is->audio_buf_index;
  360. if(len1 > len)
  361. len1 = len;
  362. memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
  363. len -= len1;
  364. stream += len1;
  365. is->audio_buf_index += len1;
  366. }
  367. }
  368. static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque)
  369. {
  370. SDL_Event event;
  371. event.type = FF_REFRESH_EVENT;
  372. event.user.data1 = opaque;
  373. SDL_PushEvent(&event);
  374. return 0; /* 0 means stop timer */
  375. }
  376. /* schedule a video refresh in ‘delay‘ ms */
  377. static void schedule_refresh(VideoState *is, int delay)
  378. {
  379. SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
  380. }
  381. void video_display(VideoState *is)
  382. {
  383. SDL_Rect rect;
  384. VideoPicture *vp;
  385. AVPicture pict;
  386. float aspect_ratio;
  387. int w, h, x, y;
  388. int i;
  389. vp = &is->pictq[is->pictq_rindex];
  390. if(vp->bmp)
  391. {
  392. if(is->video_st->codec->sample_aspect_ratio.num == 0)
  393. {
  394. aspect_ratio = 0;
  395. }
  396. else
  397. {
  398. aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) *
  399. is->video_st->codec->width / is->video_st->codec->height;
  400. }
  401. if(aspect_ratio <= 0.0)
  402. {
  403. aspect_ratio = (float)is->video_st->codec->width /
  404. (float)is->video_st->codec->height;
  405. }
  406. h = screen->h;
  407. w = ((int)(h * aspect_ratio)) & -3;
  408. if(w > screen->w)
  409. {
  410. w = screen->w;
  411. h = ((int)(w / aspect_ratio)) & -3;
  412. }
  413. x = (screen->w - w) / 2;
  414. y = (screen->h - h) / 2;
  415. rect.x = x;
  416. rect.y = y;
  417. rect.w = w;
  418. rect.h = h;
  419. SDL_DisplayYUVOverlay(vp->bmp, &rect);
  420. }
  421. }
  422. void video_refresh_timer(void *userdata)
  423. {
  424. VideoState *is = (VideoState *)userdata;
  425. VideoPicture *vp;
  426. double actual_delay, delay, sync_threshold, ref_clock, diff;
  427. if(is->video_st)
  428. {
  429. if(is->pictq_size == 0)
  430. {
  431. schedule_refresh(is, 1);
  432. }
  433. else
  434. {
  435. vp = &is->pictq[is->pictq_rindex];
  436. is->video_current_pts = vp->pts;
  437. is->video_current_pts_time = av_gettime();
  438. delay = vp->pts - is->frame_last_pts; /* the pts from last time */
  439. if(delay <= 0 || delay >= 1.0)
  440. {
  441. /* if incorrect delay, use previous one */
  442. delay = is->frame_last_delay;
  443. }
  444. /* save for next time */
  445. is->frame_last_delay = delay;
  446. is->frame_last_pts = vp->pts;
  447. /* update delay to sync to audio */
  448. ref_clock = get_master_clock(is);
  449. diff = vp->pts - ref_clock;
  450. /* Skip or repeat the frame. Take delay into account
  451. FFPlay still doesn‘t "know if this is the best guess." */
  452. if(is->av_sync_type != AV_SYNC_VIDEO_MASTER)
  453. {
  454. sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;
  455. if(fabs(diff) < AV_NOSYNC_THRESHOLD)
  456. {
  457. if(diff <= -sync_threshold)
  458. {
  459. delay = 0;
  460. }
  461. else if(diff >= sync_threshold)
  462. {
  463. delay = 2 * delay;
  464. }
  465. }
  466. }
  467. is->frame_timer += delay;
  468. /* computer the REAL delay */
  469. actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
  470. if(actual_delay < 0.010)
  471. {
  472. /* Really it should skip the picture instead */
  473. actual_delay = 0.010;
  474. }
  475. schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
  476. /* show the picture! */
  477. video_display(is);
  478. /* update queue for next picture! */
  479. if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
  480. {
  481. is->pictq_rindex = 0;
  482. }
  483. SDL_LockMutex(is->pictq_mutex);
  484. is->pictq_size--;
  485. SDL_CondSignal(is->pictq_cond);
  486. SDL_UnlockMutex(is->pictq_mutex);
  487. }
  488. }
  489. else
  490. {
  491. schedule_refresh(is, 100);
  492. }
  493. }
  494. void alloc_picture(void *userdata)
  495. {
  496. VideoState *is = (VideoState *)userdata;
  497. VideoPicture *vp;
  498. vp = &is->pictq[is->pictq_windex];
  499. if(vp->bmp)
  500. {
  501. // we already have one make another, bigger/smaller
  502. SDL_FreeYUVOverlay(vp->bmp);
  503. }
  504. // Allocate a place to put our YUV image on that screen
  505. vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width,
  506. is->video_st->codec->height,
  507. SDL_YV12_OVERLAY,
  508. screen);
  509. vp->width = is->video_st->codec->width;
  510. vp->height = is->video_st->codec->height;
  511. SDL_LockMutex(is->pictq_mutex);
  512. vp->allocated = 1;
  513. SDL_CondSignal(is->pictq_cond);
  514. SDL_UnlockMutex(is->pictq_mutex);
  515. }
  516. int queue_picture(VideoState *is, AVFrame *pFrame, double pts)
  517. {
  518. VideoPicture *vp;
  519. //int dst_pix_fmt;
  520. AVPicture pict;
  521. /* wait until we have space for a new pic */
  522. SDL_LockMutex(is->pictq_mutex);
  523. while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
  524. !is->quit)
  525. {
  526. SDL_CondWait(is->pictq_cond, is->pictq_mutex);
  527. }
  528. SDL_UnlockMutex(is->pictq_mutex);
  529. if(is->quit)
  530. return -1;
  531. // windex is set to 0 initially
  532. vp = &is->pictq[is->pictq_windex];
  533. /* allocate or resize the buffer! */
  534. if(!vp->bmp ||
  535. vp->width != is->video_st->codec->width ||
  536. vp->height != is->video_st->codec->height)
  537. {
  538. SDL_Event event;
  539. vp->allocated = 0;
  540. /* we have to do it in the main thread */
  541. event.type = FF_ALLOC_EVENT;
  542. event.user.data1 = is;
  543. SDL_PushEvent(&event);
  544. /* wait until we have a picture allocated */
  545. SDL_LockMutex(is->pictq_mutex);
  546. while(!vp->allocated && !is->quit)
  547. {
  548. SDL_CondWait(is->pictq_cond, is->pictq_mutex);
  549. }
  550. SDL_UnlockMutex(is->pictq_mutex);
  551. if(is->quit)
  552. {
  553. return -1;
  554. }
  555. }
  556. /* We have a place to put our picture on the queue */
  557. /* If we are skipping a frame, do we set this to null
  558. but still return vp->allocated = 1? */
  559. static struct SwsContext *img_convert_ctx;
  560. if (img_convert_ctx == NULL)
  561. {
  562. img_convert_ctx = sws_getContext(is->video_st->codec->width, is->video_st->codec->height,
  563. is->video_st->codec->pix_fmt,
  564. is->video_st->codec->width, is->video_st->codec->height,
  565. PIX_FMT_YUV420P,
  566. SWS_BICUBIC, NULL, NULL, NULL);
  567. if (img_convert_ctx == NULL)
  568. {
  569. fprintf(stderr, "Cannot initialize the conversion context/n");
  570. exit(1);
  571. }
  572. }
  573. if(vp->bmp)
  574. {
  575. SDL_LockYUVOverlay(vp->bmp);
  576. //dst_pix_fmt = PIX_FMT_YUV420P;
  577. /* point pict at the queue */
  578. pict.data[0] = vp->bmp->pixels[0];
  579. pict.data[1] = vp->bmp->pixels[2];
  580. pict.data[2] = vp->bmp->pixels[1];
  581. pict.linesize[0] = vp->bmp->pitches[0];
  582. pict.linesize[1] = vp->bmp->pitches[2];
  583. pict.linesize[2] = vp->bmp->pitches[1];
  584. // Convert the image into YUV format that SDL uses
  585. /*img_convert(&pict, dst_pix_fmt,
  586. (AVPicture *)pFrame, is->video_st->codec->pix_fmt,
  587. is->video_st->codec->width, is->video_st->codec->height);*/
  588. sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
  589. 0, is->video_st->codec->height, pict.data, pict.linesize);
  590. SDL_UnlockYUVOverlay(vp->bmp);
  591. vp->pts = pts;
  592. /* now we inform our display thread that we have a pic ready */
  593. if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
  594. {
  595. is->pictq_windex = 0;
  596. }
  597. SDL_LockMutex(is->pictq_mutex);
  598. is->pictq_size++;
  599. SDL_UnlockMutex(is->pictq_mutex);
  600. }
  601. return 0;
  602. }
  603. double synchronize_video(VideoState *is, AVFrame *src_frame, double pts)
  604. {
  605. double frame_delay;
  606. if(pts != 0)
  607. {
  608. /* if we have pts, set video clock to it */
  609. is->video_clock = pts;
  610. }
  611. else
  612. {
  613. /* if we aren‘t given a pts, set it to the clock */
  614. pts = is->video_clock;
  615. }
  616. /* update the video clock */
  617. frame_delay = av_q2d(is->video_st->codec->time_base);
  618. /* if we are repeating a frame, adjust clock accordingly */
  619. frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
  620. is->video_clock += frame_delay;
  621. return pts;
  622. }
  623. uint64_t global_video_pkt_pts = AV_NOPTS_VALUE;
  624. /* These are called whenever we allocate a frame
  625. * buffer. We use this to store the global_pts in
  626. * a frame at the time it is allocated.
  627. */
  628. int our_get_buffer(struct AVCodecContext *c, AVFrame *pic)
  629. {
  630. int ret = avcodec_default_get_buffer(c, pic);
  631. uint64_t *pts = (uint64_t *)av_malloc(sizeof(uint64_t));
  632. *pts = global_video_pkt_pts;
  633. pic->opaque = pts;
  634. return ret;
  635. }
  636. void our_release_buffer(struct AVCodecContext *c, AVFrame *pic)
  637. {
  638. if(pic) av_freep(&pic->opaque);
  639. avcodec_default_release_buffer(c, pic);
  640. }
  641. int video_thread(void *arg)
  642. {
  643. VideoState *is = (VideoState *)arg;
  644. AVPacket pkt1, *packet = &pkt1;
  645. int len1, frameFinished;
  646. AVFrame *pFrame;
  647. double pts;
  648. pFrame = avcodec_alloc_frame();
  649. for(;;)
  650. {
  651. if(packet_queue_get(&is->videoq, packet, 1) < 0)
  652. {
  653. // means we quit getting packets
  654. break;
  655. }
  656. pts = 0;
  657. // Save global pts to be stored in pFrame in first call
  658. global_video_pkt_pts = packet->pts;
  659. // Decode video frame
  660. len1 = avcodec_decode_video(is->video_st->codec, pFrame, &frameFinished,
  661. packet->data, packet->size);
  662. if(packet->dts == AV_NOPTS_VALUE
  663. && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE)
  664. {
  665. pts = *(uint64_t *)pFrame->opaque;
  666. }
  667. else if(packet->dts != AV_NOPTS_VALUE)
  668. {
  669. pts = packet->dts;
  670. }
  671. else
  672. {
  673. pts = 0;
  674. }
  675. pts *= av_q2d(is->video_st->time_base);
  676. // Did we get a video frame?
  677. if(frameFinished)
  678. {
  679. pts = synchronize_video(is, pFrame, pts);
  680. if(queue_picture(is, pFrame, pts) < 0)
  681. {
  682. break;
  683. }
  684. }
  685. av_free_packet(packet);
  686. }
  687. av_free(pFrame);
  688. return 0;
  689. }
  690. int stream_component_open(VideoState *is, int stream_index)
  691. {
  692. AVFormatContext *pFormatCtx = is->pFormatCtx;
  693. AVCodecContext *codecCtx;
  694. AVCodec *codec;
  695. SDL_AudioSpec wanted_spec, spec;
  696. if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams)
  697. {
  698. return -1;
  699. }
  700. // Get a pointer to the codec context for the video stream
  701. codecCtx = pFormatCtx->streams[stream_index]->codec;
  702. if(codecCtx->codec_type == CODEC_TYPE_AUDIO)
  703. {
  704. // Set audio settings from codec info
  705. wanted_spec.freq = codecCtx->sample_rate;
  706. wanted_spec.format = AUDIO_S16SYS;
  707. wanted_spec.channels = codecCtx->channels;
  708. wanted_spec.silence = 0;
  709. wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
  710. wanted_spec.callback = audio_callback;
  711. wanted_spec.userdata = is;
  712. if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
  713. {
  714. fprintf(stderr, "SDL_OpenAudio: %s/n", SDL_GetError());
  715. return -1;
  716. }
  717. is->audio_hw_buf_size = spec.size;
  718. }
  719. codec = avcodec_find_decoder(codecCtx->codec_id);
  720. if(!codec || (avcodec_open(codecCtx, codec) < 0))
  721. {
  722. fprintf(stderr, "Unsupported codec!/n");
  723. return -1;
  724. }
  725. switch(codecCtx->codec_type)
  726. {
  727. case CODEC_TYPE_AUDIO:
  728. is->audioStream = stream_index;
  729. is->audio_st = pFormatCtx->streams[stream_index];
  730. is->audio_buf_size = 0;
  731. is->audio_buf_index = 0;
  732. /* averaging filter for audio sync */
  733. is->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB));
  734. is->audio_diff_avg_count = 0;
  735. /* Correct audio only if larger error than this */
  736. is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / codecCtx->sample_rate;
  737. memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
  738. packet_queue_init(&is->audioq);
  739. SDL_PauseAudio(0);
  740. break;
  741. case CODEC_TYPE_VIDEO:
  742. is->videoStream = stream_index;
  743. is->video_st = pFormatCtx->streams[stream_index];
  744. is->frame_timer = (double)av_gettime() / 1000000.0;
  745. is->frame_last_delay = 40e-3;
  746. is->video_current_pts_time = av_gettime();
  747. packet_queue_init(&is->videoq);
  748. is->video_tid = SDL_CreateThread(video_thread, is);
  749. codecCtx->get_buffer = our_get_buffer;
  750. codecCtx->release_buffer = our_release_buffer;
  751. break;
  752. default:
  753. break;
  754. }
  755. return 0;
  756. }
  757. int decode_interrupt_cb(void)
  758. {
  759. return (global_video_state && global_video_state->quit);
  760. }
  761. int decode_thread(void *arg)
  762. {
  763. VideoState *is = (VideoState *)arg;
  764. AVFormatContext *pFormatCtx;
  765. AVPacket pkt1, *packet = &pkt1;
  766. int video_index = -1;
  767. int audio_index = -1;
  768. int i;
  769. is->videoStream=-1;
  770. is->audioStream=-1;
  771. global_video_state = is;
  772. // will interrupt blocking functions if we quit!
  773. url_set_interrupt_cb(decode_interrupt_cb);
  774. // Open video file
  775. if(av_open_input_file(&pFormatCtx, is->filename, NULL, 0, NULL)!=0)
  776. return -1; // Couldn‘t open file
  777. is->pFormatCtx = pFormatCtx;
  778. // Retrieve stream information
  779. if(av_find_stream_info(pFormatCtx)<0)
  780. return -1; // Couldn‘t find stream information
  781. // Dump information about file onto standard error
  782. dump_format(pFormatCtx, 0, is->filename, 0);
  783. // Find the first video stream
  784. for(i=0; i<pFormatCtx->nb_streams; i++)
  785. {
  786. if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO &&
  787. video_index < 0)
  788. {
  789. video_index=i;
  790. }
  791. if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO &&
  792. audio_index < 0)
  793. {
  794. audio_index=i;
  795. }
  796. }
  797. if(audio_index >= 0)
  798. {
  799. stream_component_open(is, audio_index);
  800. }
  801. if(video_index >= 0)
  802. {
  803. stream_component_open(is, video_index);
  804. }
  805. if(is->videoStream < 0 || is->audioStream < 0)
  806. {
  807. fprintf(stderr, "%s: could not open codecs/n", is->filename);
  808. goto fail;
  809. }
  810. // main decode loop
  811. for(;;)
  812. {
  813. if(is->quit)
  814. {
  815. break;
  816. }
  817. // seek stuff goes here
  818. if(is->audioq.size > MAX_AUDIOQ_SIZE ||
  819. is->videoq.size > MAX_VIDEOQ_SIZE)
  820. {
  821. SDL_Delay(10);
  822. continue;
  823. }
  824. if(av_read_frame(is->pFormatCtx, packet) < 0)
  825. {
  826. if(url_ferror(pFormatCtx->pb) == 0)
  827. {
  828. SDL_Delay(100); /* no error; wait for user input */
  829. continue;
  830. }
  831. else
  832. {
  833. break;
  834. }
  835. }
  836. // Is this a packet from the video stream?
  837. if(packet->stream_index == is->videoStream)
  838. {
  839. packet_queue_put(&is->videoq, packet);
  840. }
  841. else if(packet->stream_index == is->audioStream)
  842. {
  843. packet_queue_put(&is->audioq, packet);
  844. }
  845. else
  846. {
  847. av_free_packet(packet);
  848. }
  849. }
  850. /* all done - wait for it */
  851. while(!is->quit)
  852. {
  853. SDL_Delay(100);
  854. }
  855. fail:
  856. {
  857. SDL_Event event;
  858. event.type = FF_QUIT_EVENT;
  859. event.user.data1 = is;
  860. SDL_PushEvent(&event);
  861. }
  862. return 0;
  863. }
  864. int main(int argc, char *argv[])
  865. {
  866. SDL_Event       event;
  867. VideoState      *is;
  868. is = (VideoState *)av_mallocz(sizeof(VideoState));
  869. if(argc < 2)
  870. {
  871. fprintf(stderr, "Usage: test <file>/n");
  872. exit(1);
  873. }
  874. // Register all formats and codecs
  875. av_register_all();
  876. if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))
  877. {
  878. fprintf(stderr, "Could not initialize SDL - %s/n", SDL_GetError());
  879. exit(1);
  880. }
  881. // Make a screen to put our video
  882. #ifndef __DARWIN__
  883. screen = SDL_SetVideoMode(640, 480, 0, 0);
  884. #else
  885. screen = SDL_SetVideoMode(640, 480, 24, 0);
  886. #endif
  887. if(!screen)
  888. {
  889. fprintf(stderr, "SDL: could not set video mode - exiting/n");
  890. exit(1);
  891. }
  892. //pstrcpy(is->filename, sizeof(is->filename), argv[1]);
  893. strcpy(is->filename,argv[1]);
  894. is->pictq_mutex = SDL_CreateMutex();
  895. is->pictq_cond = SDL_CreateCond();
  896. schedule_refresh(is, 40);
  897. is->av_sync_type = DEFAULT_AV_SYNC_TYPE;
  898. is->parse_tid = SDL_CreateThread(decode_thread, is);
  899. if(!is->parse_tid)
  900. {
  901. av_free(is);
  902. return -1;
  903. }
  904. for(;;)
  905. {
  906. SDL_WaitEvent(&event);
  907. switch(event.type)
  908. {
  909. case FF_QUIT_EVENT:
  910. case SDL_QUIT:
  911. is->quit = 1;
  912. SDL_Quit();
  913. exit(0);
  914. break;
  915. case FF_ALLOC_EVENT:
  916. alloc_picture(event.user.data1);
  917. break;
  918. case FF_REFRESH_EVENT:
  919. video_refresh_timer(event.user.data1);
  920. break;
  921. default:
  922. break;
  923. }
  924. }
  925. return 0;
  926. }
时间: 2024-07-30 05:47:35

ffmpeg+sdl教程----编写一个简单的播放器6(其他的时钟同步方式)的相关文章

ffmpeg+sdl教程----编写一个简单的播放器3(为视频加入音频)

来源:http://blog.csdn.net/mu399/article/details/5814901 上个教程实现了视频的简单播放,但那是个哑巴电影,完全没有声音. 这个教程第一次用到了SDL的线程,涉及到了两个线程间的同步协调,有几个地方需要特别留意,SDL_OpenAudio库函数会打开音频设备(0是恢 复,其他的是暂停),SDL_PauseAudio库函数可以暂停或者恢复audio_callback函数的执行,程序中的这行代码 “SDL_PauseAudio(0);”执行后,让aud

ffmpeg+sdl教程----编写一个简单的播放器4(让程序更模块化)

来源:http://blog.csdn.net/mu399/article/details/5815444 音频和视频之间的同步,再那之前需要先做一些准备工作. 为了让程序更模块化,便于扩展,需要把原来main函数中的各个功能模块代码分离出来放在相应的函数中.该教程和上个教程相比代码量和难度都增加很多,比上个教程使用了更多的线程,一定要理解清楚各个函数和数据结构之间的关联以及线程之间如何协同工作. [c-sharp] view plaincopy // ffmpegExe.cpp: 主项目文件.

ffmpeg+sdl教程----编写一个简单的播放器5(同步视频到音频)

来源:http://blog.csdn.net/mu399/article/details/5816566 个人认为,这这部分教程的新增代码量虽然不是最多的,难度却是最大的,重复看了多次才明白,因为有两个问题的困扰,搞得还不清楚: 1.音频和视频既然都有各自的时间戳,各自按各自的时间戳来播放不就行了,为什么还需要同步呢? 2.如果要把视频同步到音频,怎么同步?或者说以什么标准来同步? 第一个问题的答案可能是,一是音频和视频的开始播放的时间是不一样,二是播放每帧音频或视频时可能必须把解码数据,视频

ffmpeg+sdl教程----编写一个简单的播放器2(输出视频到屏幕)

来源:http://blog.csdn.net/mu399/article/details/5814859 下面完整代码,在vc2005下编译通过.可以看到,程序运行后视频播放出来了,但是由于没有加入播放延迟,视频简直跑疯了,为视频加入延迟将在教程五中实现,目前可以简单地让程序在播放完一帧后,sleep若干秒,改善一下运行状况. [cpp] view plaincopy // ffmpegExe.cpp: 主项目文件. #include "stdafx.h" #include &quo

ffmpeg+sdl教程----编写一个简单的播放器7(处理快进快退命令)

来源:http://blog.csdn.net/mu399/article/details/5818970 这篇教程例子中的程序,让右方向按键为快进10秒,上方向按键为快进60秒,左方向按键为快退10秒,上方向按键为快退60秒,程序中的 av_seek_frame函数可能是用错了,或者函数本身的问题导致按上和右都没反应;按左和下让画面暂停,声音在很短区间内不停播放,这时再按右和下 才正常. [cpp] view plaincopy #include "libavformat/avformat.h

可视化程序设计基础(三)——一个简单的播放器(并不)

本次的作业是制作一个简单的播放器,功能仅限于播放视频和音频,虽说是简单的播放器,但其中还是有很多细节需要注意的. 问题一:布局 本来这个问题不应该是一个问题了,之前老师讲过的Stackpanel和Grid等对于布局一个播放器来说绰绰有余,但上次上课老师提到的NavigationView令我十分感兴趣,这是一个uwp应用程序中随处可见的一种布局,节省了开发者很多的时间. 所以我就着手于建立这个NavigationView了,首先我看了一下XAML Controls Gallery,然而其中关于Na

[SimplePlayer] 实现一个简单的播放器

简单的播放器需要实现一个最基本的功能:播放视频文件. 实现这个功能需要包含以下几个步骤: 从视频文件中提取视频图像 在屏幕上显示视频图像 视频帧的同步,也就是保证视频图像在合适的时间在屏幕上显示 从视频文件中提取音频 向音频设备输出音频 音频同步,也就是保证合适的时间输出合适的音频 多线程处理 音视频同步 本实现是通过ffmpeg来实现音视频的提取,通过sdl2来实现音视频的输出,版本如下: libavutil 56. 19.100 / 56. 19.100 libavcodec 58. 23.

qt实现一个简单的播放器

ui界面设计如下: 2.代码结构 3.dialog.cpp #include "dialog.h" #include "ui_dialog.h" #include<QStringList> #include<QDebug> Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) { ui->setupUi(this); ui->lb_dis->

Android开发6:Service的使用(简单音乐播放器的实现)

前言 啦啦啦~各位好久不见啦~博主最近比较忙,而且最近一次实验也是刚刚结束~ 好了不废话了,直接进入我们这次的内容~ 在这篇博文里我们将学习Service(服务)的相关知识,学会使用 Service 进行后台工作, 学会使用 Service 与 Activity 进行通信,并在此知识基础上学会使用 MediaPlayer和简单的多线程编程.使用 Handle 更新 UI,并设计成功一个简单的音乐播放器. 是不是很高大上呢~一起来学习~ 基础知识 Service作为Android四大组件之一,在每