<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          libVLC 提取視頻每一幀

          共 3703字,需瀏覽 8分鐘

           ·

          2020-08-15 01:04

          1

          什么是幀


          DVD 電影中的場景、從 YouTube 下載的剪輯、通過網(wǎng)絡(luò)攝像頭拍攝的內(nèi)容。。。無論是視頻還是動(dòng)畫,都是由一系列靜止的圖像組成。然后,這些圖像會(huì)一個(gè)接一個(gè)的播放,讓你的眼睛誤以為物體在移動(dòng)。圖像的播放速度越快,動(dòng)作看起來越流暢,畫面也越逼真。


          一般來說,想要達(dá)到自然平滑的動(dòng)態(tài)效果,播放速率應(yīng)該在每秒 24-30 張圖像之間,每個(gè)圖像被稱為一幀。因此,我們通常會(huì)看到 FPS(每秒幀數(shù))這個(gè)詞,它突出顯示了移動(dòng)速度的細(xì)節(jié),因此而得名。


          舉一個(gè)栗子 - 走路,我們看到的是這樣的:



          其實(shí),真實(shí)情況是這樣的:



          視頻文件也一樣,只不過它是將所有幀存儲(chǔ)在一起并按順序播放。對(duì)于一個(gè)典型的電影來說,存儲(chǔ)的總幀數(shù)甚至可以達(dá)到數(shù)十萬。如果要捕獲其中的某一幀圖像,則非常簡單,只需暫停視頻并按 Print Screen 鍵即可。


          但倘若要從一個(gè)視頻剪輯中提取多個(gè)連續(xù)的幀,甚至是所有幀,那么一次捕捉一個(gè)圖像是非常低效和費(fèi)時(shí)的。出于這個(gè)原因,可以用 libVLC 實(shí)現(xiàn)一個(gè)程序,用于提取想要的視頻幀,并自動(dòng)保存到圖像文件(例如:jpg 或 png)中。



          2

          主要接口


          要提取視頻中的每一幀,主要涉及以下核心 API。


          先來看第一個(gè) -?libvlc_video_set_callbacks(),用于設(shè)置回調(diào)和私有數(shù)據(jù),將解碼后的視頻渲染到內(nèi)存中的自定義區(qū)域:


          /**
          ?*? mp:媒體播放器
          ?*? lock:回調(diào)以鎖定視頻內(nèi)存(不能為 NULL)
          ?*? unlock:回調(diào)以解鎖視頻內(nèi)存(如果不需要,則為 NULL)
          ?*? display:回調(diào)以顯示視頻(如果不需要,則為 NULL)
          ?*? opaque:這三個(gè)回調(diào)的私有指針(作為第一個(gè)參數(shù))
          ?*/

          void?libvlc_video_set_callbacks(?libvlc_media_player_t?*mp,
          ?????????????????????????????????libvlc_video_lock_cb?lock,
          ?????????????????????????????????libvlc_video_unlock_cb?unlock,
          ?????????????????????????????????libvlc_video_display_cb?display,
          ?????????????????????????????????void?*opaque?)
          ;


          這個(gè)函數(shù)包含了五個(gè)參數(shù),其中有三個(gè)是函數(shù)指針:


          //?當(dāng)需要解碼新的視頻幀時(shí),就會(huì)調(diào)用 lock 回調(diào)。
          typedef?void?*(*libvlc_video_lock_cb)(void?*opaque,?void?**planes);

          //?當(dāng)視頻幀解碼完成后,將調(diào)用 unlock 回調(diào)。
          typedef?void?(*libvlc_video_unlock_cb)(void?*opaque,?void?*picture,
          ???????????????????????????????????????void?*const?*planes)
          ;

          //?當(dāng)視頻幀需要顯示時(shí),將調(diào)用 display 回調(diào)。
          typedef?void?(*libvlc_video_display_cb)(void?*opaque,?void?*picture);


          此外,還可使用?libvlc_video_set_format()?或者?libvlc_video_set_format_callbacks()?配置解碼的格式。例如,設(shè)置解碼后的視頻色度和尺寸:


          /**
          ?*? mp:媒體播放器
          ?*? chroma:標(biāo)識(shí)色度的四個(gè)字符的字符串(例如:"RV32"?或者?"YUYV")
          ?*? width:像素寬度
          ?*? height:像素高度
          ?*? pitch:線間距(以字節(jié)為單位)
          ?*/

          void?libvlc_video_set_format(?libvlc_media_player_t?*mp,?const?char?*chroma,
          ??????????????????????????????unsigned?width,?unsigned?height,
          ??????????????????????????????unsigned?pitch?)
          ;



          3

          提取每一幀


          現(xiàn)在,是時(shí)候一展身手了,來提取一個(gè)視頻中的連續(xù)幀:



          視頻比較長,為了演示,只播放一段時(shí)間(這里是 10 秒),然后提取這段時(shí)間中的幀數(shù)據(jù):


          #include?
          #include?
          #include?
          #include?
          #include?

          //?定義輸出視頻的分辨率
          #define?VIDEO_WIDTH???640
          #define?VIDEO_HEIGHT??480

          struct?Context?{
          ????QMutex?mutex;
          ????uchar?*pixels;
          };

          static?void?*lock(void?*opaque,?void?**planes)
          {
          ????struct?Context?*ctx?=?static_cast(opaque);
          ????ctx->mutex.lock();

          ????//?告訴?VLC?將解碼的數(shù)據(jù)放到緩沖區(qū)中
          ????*planes?=?ctx->pixels;

          ????return?nullptr;
          }

          //?獲取?argb?圖片并保存到文件中
          static?void?unlock(void?*opaque,?void?*picture,?void?*const?*planes)
          {
          ????Q_UNUSED(picture);

          ????struct?Context?*ctx?=?static_cast(opaque);
          ????unsigned?char?*data?=?static_cast<unsigned?char?*>(*planes);
          ????static?int?frameCount?=?1;

          ????QImage?image(data,?VIDEO_WIDTH,?VIDEO_HEIGHT,?QImage::Format_ARGB32);
          ????image.save(QString("frame_%1.png").arg(frameCount++));

          ????ctx->mutex.unlock();
          }

          static?void?display(void?*opaque,?void?*picture)
          {
          ????Q_UNUSED(picture);

          ????(void)opaque;
          }

          int?main()
          {
          ????const?char?*localMrl?=?"Sample.mkv";

          ????struct?Context?ctx;
          ????ctx.pixels?=?new?uchar[VIDEO_WIDTH?*?VIDEO_HEIGHT?*?4];
          ????memset(ctx.pixels,?0,?VIDEO_WIDTH?*?VIDEO_HEIGHT?*?4);

          ????libvlc_instance_t?*instance;
          ????libvlc_media_player_t?*player;
          ????libvlc_media_t?*media;

          ????instance?=?libvlc_new(0,?nullptr);
          ????media?=?libvlc_media_new_path(instance,?localMrl);
          ????player?=?libvlc_media_player_new_from_media(media);

          ????//?設(shè)置回調(diào),用于提取幀或者在界面上顯示。
          ????libvlc_video_set_callbacks(player,?lock,?unlock,?display,?&ctx);
          ????libvlc_video_set_format(player,?"RGBA",?VIDEO_WIDTH,?VIDEO_HEIGHT,?VIDEO_WIDTH?*?4);

          ????libvlc_media_player_play(player);

          ????QThread::sleep(10);

          ????libvlc_media_release(media);
          ????libvlc_media_player_release(player);
          ????libvlc_release(instance);

          ????return?0;
          }


          這里為了保存圖片,我們用到了 Qt 中的一個(gè)類 - QImage。該類提供了與硬件無關(guān)的圖像表示,允許直接訪問像素?cái)?shù)據(jù),并可用作繪圖設(shè)備。


          ·END·
          ?

          作者:一去、二三里
          愛學(xué)習(xí),愛編程,愛生活。
          歡迎來撩,一起暢談程序人生!

          點(diǎn)個(gè)在看,么么噠!

          瀏覽 215
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  夜夜躁很很躁日日躁麻豆 | 亚洲欧洲视频 | 天堂成人在线观看 | 又黄又爽又粗又大又长又硬视屏 | g国产欧美一区二区精品性色超碰 |