Linux驅動20 --- FFMPEG視頻API

目錄

一、FFMPEG 視頻 API 的使用

1.1 介紹

1.2 整體編程過程

????????獲取核心上下文指針

????????打開輸入流文件

????????獲取輸入流

????????獲取編碼器

????????初始化解碼器

????????申請輸出流指針

????????獲取顯示數據空間大小

????????申請輸出顯示空間

????????綁定輸出流和輸出顯示空間

????????申請格式轉換上下文

????????申請輸入流指針

????????讀取一幀數據

????????發送給解碼器

????????從解碼器讀取一幀數據

????????格式轉換

????????顯示在屏幕上

1.3 參數擴展

????????資源的釋放

????????數據格式轉換

????????AVFormatcontext

????????AVStream

????????AVCodecContext

????????AVCodecParameters

????????AVCodec

????????AVPacket

????????AVFrame

1.4 URL

1.5 程序的編譯執行

二、LVGL 列表

1、列表和目錄操作結合

2、點擊不同的列表按鈕,獲取要播放的視頻文件名

3、列表隱藏


一、FFMPEG 視頻 API 的使用

1.1 介紹

????????主要做視頻的解碼 --- 視頻的播放

????????視頻在最終轉換為 RGB 格式之后,需要填充在屏幕上,然后完成播放

????????視頻解碼,然后借助工具 --- LVGL,讓圖片控件切換顯示的圖像

????????FFMPEG、LVGL

這是一個 FFMPEG 可以實現解碼的程序需要的所有 API 的解析

1.2 整體編程過程

????????獲取核心上下文指針

????????????????之前的編程中,對于結構體都是叫核心結構體

????????????????但是在 FFMPEG 中,他叫上下文 --- context ? ? ? ??

????????函數頭文件

????????????????#include "libavformat/avformat.h"

????????函數功能

????????????????創建一個AVFormatcontext,申請內存空間,并初始化一些初始變量

????????函數原型

????????????????AVFormatContext *avformat_alloc_context(void)

????????打開輸入流文件

????????函數頭文件

????????????????#include "libavformat/avformat.h"

????????函數功能

????????????????打開一個文件并解析。可解析的內容包括:視頻流、音頻流、視頻流參數、音頻流參數、視頻幀索引

????????函數原型

????????????????int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options);

????????函數參數

????????????????AVFormatContext **ps:格式化的上下文。要注意,如果傳入的是一個AVFormatContext*的指針,則該空間須自己手動清理,若傳入的指針為空,則FFmpeg會內部自己創建。

????????????????const char *url:傳入的地址。支持http,RTSP,以及普通的本地文件。地址最終會存入到AVFormatContext結構體當中。

????????????????AVInputFormat *fmt:指定輸入的封裝格式。一般傳NULL,由FFmpeg自行探測。

????????????????AVDictionary **options:其它參數設置。它是一個字典,用于參數傳遞,不傳則寫NULL。參見:libavformat/options_table.h,其中包含了它支持的參數設置。

????????函數返回值

????????????????成功返回0,失敗返回負數

????????獲取輸入流

????????函數功能

????????????????查找格式和索引。有些早期格式它的索引并沒有放到頭當中,需要你到后面探測,就會用到此函數

????????函數原型

????????????????int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);

????????函數參數

????????????????fmt_ctx:AVFormatContext結構體指針,表示媒體文件的格式上下文,其中包含已經打開的媒體文件的信息和媒體文件中每個音視頻流的信息。

????????????????其中成員變量streams[0]表示視頻流,streams[1]表示音頻流

????????????????options:AVDictionary結構體指針,用于傳遞選項。目前已經不使用,傳NULL即可。

????????函數返回值

????????????????成功返回>=0的數

????????獲取編碼器

????????函數功能

????????????????FFmpeg提供兩種方式查找解碼器,通過codecId查找avcodec_find_decoder()與通過名字查找avcodec_find_decoder_by_name()。同樣地,也提供兩種方式查找編碼器,通過codecId查找avcodec_find_encoder()與通過名字查找avcodec_find_encoder_by_name()。源碼位于libavcodec/allcodecs.c中

????????函數原型

????????????????AVCodec *avcodec_find_decoder(enum AVCodecID id)

????????函數參數

????????????????在AVFormatcontext上下文指針的視頻流下的codec中的codec_id有當前視頻的編碼器格式

????????????????項目中可以使用AV_CODEC_ID_H264

????????????????編解碼器列表來自libavcodec/allcodecs.c,有聲明全局變量

????????函數返回值

????????????????成功返回需要的解碼器指針

????????初始化解碼器

????????函數功能

????????????????初始化一個視音頻編解碼器的AVCodecContext

????????函數原型

????????????????int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)

????????函數參數

????????????????avctx:需要初始化的AVCodecContext。

????????????????codec:輸入的AVCodec

????????????????options:一些選項。例如使用libx264編碼的時候,“preset”,“tune”等都可以通過該參數設置。

????????函數返回值

????????????????成功返回0,失敗返回負數

????????申請輸出流指針

????????函數功能

????????????????void *av_malloc(size_t size)主要作用是根據傳入的size大小來調用c的malloc函數來開辟一塊內存空間并且返回指向開辟內存空間的指針

????????函數原型

????????????????void *av_malloc(size_t size)

????????函數參數

????????獲取顯示數據空間大小

????????頭文件

????????????????#include "libavutil/imgutils.h"

????????函數功能

????????????????通過指定像素格式、圖像寬、圖像高來計算所需的內存大小

????????函數原型

????????????????int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align)

????????函數參數

????????AVPixelFormat:

????????????????輸出數據的格式AV_PIX_FMT_RGB24?或AV_PIX_FMT_ABGR

????????width:

????????????????輸出數據的寬度,根據自己的情況而定

????????height:

????????????????輸出數據的高度,根據自己的情況而定

????????align:此參數是設定內存對齊的對齊數,也就是按多大的字節進行內存對齊。比如設置為1,表示按1字節對齊,那么得到的結果就是與實際的內存大小一樣。再比如設置為4,表示按4字節對齊。也就是內存的起始地址必須是4的整倍數

????????申請輸出顯示空間

????????函數功能

????????????????分配AVFrame并將其字段設置為默認值。主要該函數只分配AVFrame的空間,它的data字段的指定的buffer需要其它函數分配

????????函數原型

????????????????AVFrame *av_frame_alloc(void)

????????函數參數

????????????????AVFrame結構體,它比較重要的字段有:

????????????????data[AV_NUM_DATA_POINTERS]:存放解碼后的原始媒體數據的指針數組。

????????? ? ??對于視頻數據而言,planar(YUV420)格式的數據,Y、U、V分量會被分別存放在data[0]、data[1]、data[2]……中。packet格式的數據會被存放在data[0]中。

? ? ? ? ? ? ? ??對于音頻數據而言,data數組中,存放的是channel的數據,例如,data[0]、data[1]、data[2]分別對應channel 1,channel 2 等。

????????????????linesize[AV_NUM_DATA_POINTERS]:視頻或音頻幀數據的行寬數組。

????????????????????????對video而言:每個圖片行的字節大小。linesize大小應該是CPU對齊的倍數,對于現代pc的CPU而言,即32或64的倍數。

????????????????????????對audio而言:代表每個平面的字節大小。只會使用linesize[0]。 對于plane音頻,每個通道 的plane必須大小相同。

????????????????**extended_data:對于視頻數據:只是簡單的指向data[]。

????????????????????????對于音頻數據:planar音頻,每個通道都有一個單獨的數據指針,而linesize [0]包含每個通道緩沖區的大小。 對于packet音頻,只有一個數據指針,linesize [0]包含所有通道的緩沖區總大小。

????????????????key_frame:當前幀是否為關鍵幀,1表示是,0表示不是。

????????????????pts:以time_base為單位的呈現時間戳(應向用戶顯示幀的時間)

????????綁定輸出流和輸出顯示空間

????????函數功能

????????????????根據指定的圖像參數(顯示數據)和提供的數組設置輸出數據指針和行大小

????????函數原型

????????????????int av_image_fill_arrays(uint8_t **dst_data, int *dst_linesize, const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align)

????????函數參數

????????????????dst_data:需要開辟空間的數據指針

????????????????????????????????AVFrame的成員data

????????????????dst_linesize: dst_data中要填充的圖像的行大小

????????????????????????????????AVFrame的成員linesize

????????????????*src:?緩沖區將包含或包含實際圖像數據,可以為NULL

????????????????pix_fmt:?顯示圖像的像素格式

????????????????width:申請src內存時指定的寬度

????????????????height:申請scr內存時指定的高度

????????????????align:申請src內存時指定的對齊字節數

????????函數返回值

????????????????成功返回大于0的數,失敗返回負數

????????(a)計算所需內存大小av_image_get_bufferz_size()

????????(b)按計算的內存大小申請所需內存 av_malloc()

????????(c)對申請的內存進行格式化av_image_fill_arrays()

????????申請格式轉換上下文

????????函數功能

????????????????獲取一個上下文指針

????????函數頭文件

????????????????#include "libswscale/swscale.h"

????????函數原型

????????????????struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, int dstW, int dstH, enum AVPixelFormat dstFormat, int flags, SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param)

????????函數參數

????????參數1:被轉換源的寬

????????????????AVFormatContext的視頻流的codecpar中的width

????????參數2:被轉換源的高

????????????????AVFormatContext的視頻流的codecpar中的height

????????參數3:被轉換源的格式,以直接用枚舉的代號表示eg:AV_PIX_FMT_YUV420P這些枚舉的格式在libeg:YUV、RGB……(枚舉格式,也可avutil/pixfmt.h中列出)

????????????????AVFormatContext的視頻流的codec中的pix_fmt

????????參數4:轉換后指定的寬

????????參數5:轉換后指定的高

????????參數6:轉換后指定的格式

????????參數7:轉換所使用的算法

????????????????#define SWS_FAST_BILINEAR 1

????????????????#define SWS_BILINEAR 2

????????????????#define SWS_BICUBIC 4

????????????????#define SWS_X 8

????????????????#define SWS_POINT 0x10

????????????????#define SWS_AREA 0x20

????????????????#define SWS_BICUBLIN 0x40

????????????????#define SWS_GAUSS 0x80

????????????????#define SWS_SINC 0x100

????????????????#define SWS_LANCZOS 0x200

????????????????#define SWS_SPLINE 0x400

????????參數8:NULL參數9:NULL參數10:NULL

????????申請輸入流指針

????????函數功能

????????????????av_packet_alloc分配AVPacket以后,調用av_init_packet對AVPacket的成員變量進行初始化賦值

????????函數原型

????????????????AVPacket *av_packet_alloc(void)

????????讀取一幀數據

????????函數功能
????????????????讀取碼流中的音頻若干幀或者視頻一幀
????????函數原型
????????????????int av_read_frame(AVFormatContext *s, AVPacket *pkt)
????????函數參數
????????????????AVFormatContext *s // 文件格式上下文,輸入的AVFormatContext
????????????????AVPacket *pkt //這個值不能傳NULL,必須是一個空間,輸出的AVPacket
????????函數返回值
????????????????成功返回0,到達結尾或者失敗返回負數

????????發送給解碼器

????????函數功能

????????????????將一個packet放入到隊列中等待解碼。并不是一個packet,就代表一個frame,解碼操作是在該函數中進行的。完成此操作后,解碼后的數據放在avctx->internal->buff_frame中

????????函數原型

????????????????int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)

????????函數參數

????????????????AVCodecContext *avctx:第一個參數與舊的接口一致,是視頻解碼的上下文,包含解碼器。

????????????????const AVPacket *avpkt: 編碼的音視頻幀數據

????????從解碼器讀取一幀數據

????????函數功能

????????????????進行一個拷貝的操作,將avctx中解碼后的數據拷貝給avframe

????????函數原型

????????????????int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)

????????函數參數

????????????????AVCodecContext *avctx:第一個參數視頻解碼的上下文,與上面接口一致。

????????????????AVFrame *frame:解碼后的視頻幀數據。

????????格式轉換

????????函數功能

????????????????對圖像的大小進行縮放。轉換圖像格式跟顏色空間,例如把YUYV422轉成RGB24。轉換像素格式的存儲布局,例如把 YUYV422 轉成 YUV420P ,YUYV422 是 packed 的布局,YUV 3 個分量是一起存儲在 data[0] 里面的。而 YUV420P 是 planner 的布局,YUV 分別存儲在 data[0] ~ data[2]。

????????函數原型

????????????????int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],

??????????????????????????????????????????????const int srcStride[], int srcSliceY, int srcSliceH,

??????????????????????????????????????????????uint8_t *const dst[], const int dstStride[])

????????函數參數

????????????????第一個參數即是由?sws_getContext 所取得的參數。?

????????????????第二個?src 及第六個?dst 分別指向input 和 output 的 buffer。?

????????????????????????input指數據來源,即為avcodec_receive_frame函數第二個參數中的data成員

????????????????????????output指數據轉換后存放的位置,需要額外的AVFrame指針

????????????????第三個srcStride 及第七個?dstStride 分別指向 input 及 output 的 stride;如果不知道什么是 stride,姑且可以先把它看成是每一列的 byte 數。

????????????????????????即為AVFrame的linesize成員

????????????????第四個srcSliceY,就注釋的意思來看,是指第一列要處理的位置;從頭處理,所以直接填0。想知道更詳細說明的人,可以參考swscale.h 的注釋。

????????????????第五個srcSliceH指的是 source slice 的高度。

????????????????????????即為AVFrame的height成員

????????顯示在屏幕上

????????????????在播放視頻之前加一張圖片,主要是為了提供一個更好的用戶體驗,避免空白或閃爍的顯示效果,確保界面在視頻播放開始時具有良好的視覺過渡。

1.3 參數擴展

????????資源的釋放

????????????????avformat_close_input

????????????????avformat_free_context

????????數據格式轉換

void rgb_to_argb(uint8_t * rgbdata,uint8_t * argbdata,int w,int h){int i =0,j=0;for(i = 0 ; i < h;i++){for(j = 0; j<w;j++){argbdata[j*4+i*w*4 + 3] = 0xFF;//透明度argbdata[j*4+i*w*4 + 0] = rgbdata[j*3+i*w*3 + 2];argbdata[j*4+i*w*4 + 1] = rgbdata[j*3+i*w*3 + 1];argbdata[j*4+i*w*4 + 2] = rgbdata[j*3+i*w*3 + 0];}}}

????????AVFormatcontext

struct AVInputFormat *iformat;//輸入數據的封裝格式。僅解封裝用,由avformat_open_input()設置。struct AVOutputFormat *oformat;//輸出數據的封裝格式。僅封裝用,調用者在avformat_write_header()之前設置。AVIOContext *pb;// I/O上下文。解封裝:由用戶在avformat_open_input()之前設置(然后用戶必須手動關閉它)或通過avformat_open_input()設置。封裝:由用戶在avformat_write_header()之前設置。 調用者必須注意關閉/釋放IO上下文。unsigned int nb_streams;//AVFormatContext.streams中元素的個數。
AVStream **streams;//文件中所有流的列表。char filename[1024];//輸入輸出文件名。int64_t start_time;//第一幀的位置。int64_t duration;//流的持續時間int64_t bit_rate;//總流比特率(bit / s),如果不可用則為0。int64_t probesize;//從輸入讀取的用于確定輸入容器格式的數據的最大大小。僅封裝用,由調用者在avformat_open_input()之前設置。AVDictionary *metadata;//元數據AVCodec *video_codec;//視頻編解碼器AVCodec *audio_codec;//音頻編解碼器AVCodec *subtitle_codec;//字母編解碼器AVCodec *data_codec;//數據編解碼器int (*io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options);//打開IO stream的回調函數。void (*io_close)(struct AVFormatContext *s, AVIOContext *pb);//關閉使用AVFormatContext.io_open()打開的流的回調函數。

????????AVStream

int index; 標識該音頻/視頻流int id; 流的標識,依賴于具體的容器格式。解碼libavformat,編碼由用戶設置,用戶不設置則使用libavformatAVCodecContext *codec; 流對應與AVCodecContext結構,調用avformat_open_input設置AVRational time_base; 表示幀時間戳的基本單位。通過該值可以把PTS,DTS轉化為真正的時間,其他結構體中也有這個字段,只有AVStream 中的time_base為真正的時間。int64_t start_time; 流的起始時間,以流的基準時間為單位int64_t duration; 流的持續時間,如果源文件未指定持續時間,但指定了比特率,則將根據比特率和文件大小估計該值。int64_t nb_frames; 流中幀的數據,為0或者已知AVDictionary *metadata; 元數據AVRational sample_aspect_ratio; 樣本長寬比AVRational avg_frame_rate; 評價幀率,解封裝時:在創建流時設置或者在avformat_find_stream_info()中設置;封裝時調用avformat_write_header()設置AVCodecParameters *codecpar; 編解碼器參數int64_t first_dts; 第一個dtsint64_t cur_dts; 當前dtsint probe_packets; 編碼器用戶probe的包的個數int codec_info_nb_frames; 在avformat_find_stream_info()期間已經解封裝的幀數AVPacket attached_pic;附帶的一些圖片int request_probe; 流探測狀態,-1表示完成,0表示沒有探測請求,rest執行探測int skip_to_keyframe; 是否丟棄所有內容直接跳到關鍵幀int skip_samples;在下一個數據表解碼的幀開始要跳過的采樣數int64_t start_skip_samples;從流的開始要跳過的采樣的數量int64_t first_discard_sample; 如果不是0,從流中丟棄第一個音頻的樣本int nb_decoded_frames; 內部解碼的幀數int64_t pts_reorder_error[MAX_REORDER_DELAY+1];uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1]; 內部數據從pts到dtsint64_t last_dts_for_order_check; 內部數據用于分析dts和探測mpeg流的錯誤uint8_t dts_ordered;uint8_t dts_misordered;AVRational display_aspect_ratio; 顯示的寬高比

????????AVCodecContext

enum AVMediaType codec_type; 編解碼器的類型const struct AVCodec  *codec; 編解碼器,初始化后不可更改enum AVCodecID codec_id;  編解碼器的idint64_t bit_rate; 平均比特率uint8_t *extradata; int extradata_size; 針對特定編碼器包含的附加信息AVRational time_base; 根據該參數可以將pts轉化為時間int width, height; 每一幀的寬和高int gop_size;  一組圖片的數量,編碼時用戶設置,解碼時不使用enum AVPixelFormat pix_fmt; 像素格式,編碼時用戶設置,解碼時可由用戶指定,但是在分析數據會被覆蓋用戶的設置int refs; 參考幀的數量enum AVColorSpace colorspace; YUV色彩空間類型enum AVColorRange color_range; MPEG JPEG YUV范圍int sample_rate; 采樣率 僅音頻int channels; 聲道數(音頻)enum AVSampleFormat sample_fmt; //采樣格式int frame_size; 每個音頻幀中每個聲道的采樣數量int profile;配置類型int level;級別

????????AVCodecParameters

????????AVCodec

const char *name; //編解碼器名字const char *long_name; //編解碼器全名enum AVMediaType type; //編解碼器類型enum AVCodecID id; //編解碼器IDconst AVRational *supported_framerates; //支持幀率(視頻)const enum AVPixelFormat *pix_fmts; //支持像素格式(視頻)const int *supported_samplerates; //支持音頻采樣率(音頻)const enum AVSampleFormat *sample_fmts; //支持采樣格式(音頻)const uint64_t *channel_layouts; //支持聲道數(音頻)const AVClass *priv_class; //私有數據

????????AVPacket

AVPacket中的字段可用分為兩部分:數據的緩存及管理,關于數據的屬性說明。關于數據的屬性有以下字段:pts 顯示時間戳dts 解碼時間戳stream_index Packet所在stream的indexflats 標志,其中最低為1表示該數據是一個關鍵幀duration 數據的時長,以所屬媒體流的時間基準為單位pos 數據在媒體流中的位置,未知則值為-1convergence_duration 該字段已被deprecated,不再使用數據緩存,AVPacket本身只是個容器,不直接的包含數據,而是通過數據緩存的指針引用數據。AVPacket中包含有兩種數據data 指向保存壓縮數據的指針,這就是AVPacket實際的數據。side_data 容器提供的一些附加數據buf 是AVBufferRef類型的指針,用來管理data指針引用的數據緩存的,其使用在后面介紹

????????AVFrame

typedef struct AVFrame {#define AV_NUM_DATA_POINTERS 8uint8_t *data[AV_NUM_DATA_POINTERS]; // 存放媒體數據的指針數組int linesize[AV_NUM_DATA_POINTERS]; // 視頻或音頻幀數據的行寬uint8_t **extended_data; // 音頻或視頻數據的指針數組。int width, height; // 視頻幀的款和高/*** number of audio samples (per channel) described by this frame*/int nb_samples; // 當前幀的音頻采樣數(每個通道)int format; // 視頻幀的像素格式,見enum AVPixelFormat,或音頻的采樣格式,見enum AVSampleFormaint key_frame; // 當前幀是否為關鍵幀,1表示是,0表示不是。AVRational sample_aspect_ratio; // 視頻幀的樣本寬高比int64_t pts; // 以time_base為單位的呈現時間戳(應向用戶顯示幀的時間)。int64_t pkt_dts; // 從AVPacket復制而來的dts時間,當沒有pts時間是,pkt_dts可以替代pts。int coded_picture_number; // 按解碼先后排序的,解碼圖像數int display_picture_number; // 按顯示前后排序的,顯示圖像數。int quality; // 幀質量,從1~FF_LAMBDA_MAX之間取之,1表示最好,FF_LAMBDA_MAX之間取之表示最壞。void *opaque; // user的私有數據。int interlaced_frame; // 圖片的內容是隔行掃描的(交錯幀)。int top_field_first; // 如果內容是隔行掃描的,則首先顯示頂部字段。int sample_rate; // 音頻數據的采樣率uint64_t channel_layout; // 音頻數據的通道布局。/*** AVBuffer引用,當前幀數據。 如果所有的元素為NULL,則此幀不是引用計數。 必須連續填充此數組,* 即如果buf [i]為非NULL,j <i,buf[j]也必須為非NULL。** 每個數據平面最多可以有一個AVBuffer,因此對于視頻,此數組始終包含所有引用。* 對于具有多于AV_NUM_DATA_POINTERS個通道的平面音頻,可能有多個緩沖區可以容納在此陣列中。* 然后額外的AVBufferRef指針存儲在extended_buf數組中。*/AVBufferRef *buf[AV_NUM_DATA_POINTERS];AVBufferRef **extended_buf; // AVBufferRef的指針int        nb_extended_buf; // extended_buf的數量enum AVColorSpace colorspace; // YUV顏色空間類型。int64_t best_effort_timestamp; // 算法預測的timestampint64_t pkt_pos; // 記錄上一個AVPacket輸入解碼器的位置。int64_t pkt_duration; // packet的durationAVDictionary *metadata;int channels; // 音頻的通道數。int pkt_size; // 包含壓縮幀的相應數據包的大小。} AVFrame;

1.4 URL

????????指一個拉流地址 --- 音頻流和視頻流的地址

????????給你一個 IP,你可以從這個 IP 上獲取持續的信息

????????URL(Uniform Resource Locator)是指統一資源定位符

1.5 程序的編譯執行

????????問題來源

????????1、LVGL 工程

????????2、程序問題

????????3、視頻問題

二、LVGL 列表

1、列表和目錄操作結合

????????就可以做一個播放的菜單

????????glob 函數

????????glob 函數獲取一個路徑下所有的.mp4 文件

????????將文件名作為 list 列表的按鈕文本填上

2、點擊不同的列表按鈕,獲取要播放的視頻文件名

????????執行寫的程序去播放

3、列表隱藏

????????列表一直顯示比較遮擋視線

????????將大小改成 0,0;如果 0,0 不行,就改成 1,1?

代碼

video

#include <stdio.h>
#include "lvgl.h"
#include "custom.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
#include <pthread.h>
#include <unistd.h>void *pthread_video_func(void *argv);void custom_init(lv_ui *ui)
{/* Add your codes here */pthread_t pd = 0;pthread_create(&pd, NULL, pthread_video_func, NULL);pthread_detach(pd);}uint8_t outdata[4 * 1024 * 600];    //4字節,1024*600像素點個數lv_img_dsc_t _my_ChMkJlbKzGCIAglRAAT73pUukQsAALI1gK_rlQABPv2931_alpha_1024x600 = {.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,.header.always_zero = 0,.header.reserved = 0,.header.w = 1024,.header.h = 600,.data_size = 614400 * LV_IMG_PX_SIZE_ALPHA_BYTE,.data = outdata,
};//LVGL是一個持續運行的進程
//如果阻塞LVGL的主進程 --- 會導致程序直接結束
void *pthread_video_func(void *argv)
{// 1.獲取核心上下文指針AVFormatContext * avfmt  = avformat_alloc_context();// 2.打開輸入流文件avformat_open_input(&avfmt, "/home/lwl/GUI-Guider-Projects/mp4file/cf.mp4", NULL, NULL);// 3.獲取輸入流avformat_find_stream_info(avfmt, NULL); //到此會獲取// avfmt->streams[0] --- 視頻流// avfmt->streams[1] --- 音頻流// 4.獲取編碼器AVCodecContext * avcodectx = avfmt->streams[0]->codec;AVCodec *avcodec = avcodec_find_decoder(avcodectx->codec_id);// 5.初始化解碼器avcodec_open2(avcodectx, avcodec, NULL); // 申請輸出顯示空間 --- 得到的數據需要一塊空間存放//申請空間大小 --- 和圖像的格式,以及格式分辨率有關//enum AVPixelFormatint size = av_image_get_buffer_size(AV_PIX_FMT_BGRA, 1024, 600, 1);uint8_t *data = av_malloc(size);    //后續得到空間首地址,最終使用的是data這個空間,但是視頻格式轉換后只能放在輸出流指針中// 申請輸出流指針AVFrame * avfrm = av_frame_alloc(); //這個是最終的frm// 綁定輸出流和輸出顯示空間av_image_fill_arrays(avfrm->data, avfrm->linesize, data, AV_PIX_FMT_BGRA, 1024, 600, 1);// 申請格式轉換上下文struct SwsContext * swsctx = sws_getContext(avfmt->streams[0]->codecpar->width, avfmt->streams[0]->codecpar->height, avcodectx->pix_fmt, 1024, 600, AV_PIX_FMT_BGRA, SWS_GAUSS, NULL, NULL, NULL);// 10.申請輸入流指針AVPacket * avpkt = av_packet_alloc();   //存放輸入流中一幀圖像AVFrame * tempfrm = av_frame_alloc(); // 11.讀取一幀數據while(1){ if(!run_flag){sleep(1);   //主動釋放cpu資源continue;}if(av_read_frame(avfmt, avpkt) != 0){break;}if(avpkt->stream_index == 1){//音頻數據不做處理,如果不處理就會很卡continue;}// 發送給解碼器avcodec_send_packet(avcodectx, avpkt);// 從解碼器讀取一幀數據avcodec_receive_frame(avcodectx, tempfrm); //解碼后的數據還沒有進行格式轉換 --- 需要定義一個中間變量// 格式轉換sws_scale(swsctx, tempfrm->data, tempfrm->linesize, 0, tempfrm->height, avfrm->data, avfrm->linesize);//此時此刻,在data空間中就存放了得到的最終顯示數據memcpy(outdata, data, sizeof(outdata));// 顯示在屏幕上lv_img_set_src(self_ui->screen_img_1, &_my_ChMkJlbKzGCIAglRAAT73pUukQsAALI1gK_rlQABPv2931_alpha_1024x600);usleep(33000);}
}

list 記得添加事件

#include <stdio.h>
#include "lvgl.h"
#include "custom.h"
#include <glob.h>
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
#include <pthread.h>
#include <unistd.h>void my_add_list_btn(lv_ui *ui, char *name);void custom_init(lv_ui *ui)
{/* Add your codes here */glob_t fn = {0};//顯示歌單glob("/home/lwl/GUI-Guider-Projects/mp4file/*.mp4", 0, NULL, &fn);//lwl/GUI-Guider-Projects/mp4file/for(int i = 0; i < fn.gl_pathc; i++){printf("%d.%s\n", i + 1, fn.gl_pathv[i] + 38);//glob函數打印歌單38my_add_list_btn(ui, fn.gl_pathv[i] + 38);}globfree(&fn);}void my_add_list_btn(lv_ui *ui, char *name)
{lv_obj_t *btn = lv_list_add_btn(ui->screen_list_1, LV_SYMBOL_BATTERY_3, name);lv_style_set_pad_top(&style_screen_list_1_extra_btns_main_default, 5);lv_style_set_pad_left(&style_screen_list_1_extra_btns_main_default, 5);lv_style_set_pad_right(&style_screen_list_1_extra_btns_main_default, 5);lv_style_set_pad_bottom(&style_screen_list_1_extra_btns_main_default, 5);lv_style_set_border_width(&style_screen_list_1_extra_btns_main_default, 0);lv_style_set_text_color(&style_screen_list_1_extra_btns_main_default, lv_color_hex(0x0D3055));lv_style_set_text_font(&style_screen_list_1_extra_btns_main_default, &lv_font_montserratMedium_32);lv_style_set_text_opa(&style_screen_list_1_extra_btns_main_default, 255);lv_style_set_radius(&style_screen_list_1_extra_btns_main_default, 3);lv_style_set_bg_opa(&style_screen_list_1_extra_btns_main_default, 0);lv_obj_add_style(btn, &style_screen_list_1_extra_btns_main_default, LV_PART_MAIN | LV_STATE_DEFAULT);// 為按鈕添加點擊事件lv_obj_add_event_cb(btn, screen_list_1_item0_event_handler, LV_EVENT_CLICKED, ui);}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/91348.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/91348.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/91348.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenBayes 一周速覽丨Self Forcing 實現亞秒級延遲實時流視頻生成;邊緣AI新秀,LFM2-1.2B采用創新性架構超越傳統模型

公共資源速遞 This Weekly Snapshots &#xff01; 5 個公共數據集&#xff1a; * AF-Chat 音頻對話文本數據集 * ArtVIP 機器交互式圖像數據集 * Updesh 印度語合成文本數據集 * Medical Information 藥品信息數據集 * Nemotron-Math-HumanReasoning 數學推理數據集…

[NOIP2002 提高組] 均分紙牌

題目描述有N堆紙牌&#xff0c;編號分別為 1,2,…,N。每堆上有若干張&#xff0c;但紙牌總數必為N的倍數。可以在任一堆上取若干張紙牌&#xff0c;然后移動。移牌規則為&#xff1a;在編號為1堆上取的紙牌&#xff0c;只能移到編號為2的堆上&#xff1b;在編號為N的堆上取的紙…

【音視頻】WebRTC-Web 音視頻采集與播放

一、打開攝像頭 打開攝像頭首先需要有一個html的video標簽&#xff1a; id "local-video"&#xff0c;是為了后續的js腳本調用這個對象autoplay是設置打開后自動播放&#xff0c;playsinline則是為了兼容移動端 <video id "local-video" autoplay p…

數據治理平臺如何選?深度解析國產化全棧方案與行業落地實踐

“數據治理平臺廠商有哪些&#xff1f;”國內主流廠商包括阿里云、華為、百分點科技等&#xff0c;各有所長。其中&#xff0c;百分點科技憑借在應急管理、智慧公安及央國企數字化領域的深度實踐&#xff0c;打造了行業特色鮮明的數據治理解決方案。百分點科技的數據治理解決方…

限流算法詳解:固定窗口、滑動窗口、令牌桶與漏桶算法全面對比

限流&#xff08;Rate Limiting&#xff09;是保障系統穩定性和服務質量的關鍵機制&#xff0c;尤其在高并發、突發流量、攻擊防護等場景中至關重要。本文將詳細介紹四種主流限流算法&#xff1a;固定窗口&#xff08;Fixed Window&#xff09;滑動窗口&#xff08;Sliding Win…

Sentinel 搭建應用層面與網關層面的流控保護

源碼&#xff1a;妖精的尾巴/spring-cloud-alibaba Nacos 和 Sentinel Dashboard 我這里全是使用window 本地運行的&#xff0c;需要自行下載運行 服務層面&#xff1a; 當你在某個具體的服務上使用Sentinel時&#xff0c;更多的是關注該服務內部資源的保護。例如&#xff0c…

純血鴻蒙 AudioRenderer+AudioCapturer+RingBuffer 實現麥克風采集+發聲

總共兩個類&#xff0c;放到代碼里&#xff0c;就可以快速完成K歌的效果&#xff0c;但應用層這么做延遲是比較高的&#xff0c;只是做一個分享。 類代碼 import { audio } from kit.AudioKit; import { BusinessError } from kit.BasicServicesKit; import { AudioBufferFlow,…

洛谷 P1601 A+B Problem(高精)普及-

題目描述 高精度加法&#xff0c;相當于 ab problem&#xff0c;不用考慮負數。 輸入格式 分兩行輸入。a,b≤10500a,b \leq 10^{500}a,b≤10500。 輸出格式 輸出只有一行&#xff0c;代表 ababab 的值。 輸入輸出樣例 #1 輸入 #1 1 1輸出 #1 2輸入輸出樣例 #2 輸入 #2 1001 909…

Matrix Theory study notes[6]

文章目錄linear spacereferenceslinear space a basis of linear space VkV^kVk,which is x1,x2,...xkx_1,x_2,...x_kx1?,x2?,...xk?,can be called as a coordinate system.let vector v∈Vkv \in V^kv∈Vk and it can be linear expressed on this basis as va1x1a2x2...…

專線與專線之間的區別

下面我們從定義、技術特點、適用場景、優缺點等多個維度來詳細對比&#xff1a;? 一、四種方案簡要定義技術方案定義MPLS 專線運營商基于 MPLS 技術提供的私有虛擬網絡&#xff0c;邏輯隔離、安全可靠VPN over Internet利用公網加密通道&#xff08;如IPSec&#xff09;構建虛…

Git工作流:團隊協作的最佳實踐

目錄 一、什么是 Git 工作流&#xff1f;為什么需要它&#xff1f; 二、基礎&#xff1a;Git 分支核心概念 三、主流 Git 工作流實戰指南 1. 集中式工作流&#xff08;Centralized Workflow&#xff09;&#xff1a;適合小團隊 / 新手 操作步驟&#xff1a; 優缺點&#…

算法競賽階段二-數據結構(35)數據結構單鏈表模擬實現

//鏈表--鏈式存儲的線性表 //存信息和下一個節點位置&#xff0c;數據域和指針域合起來叫節點 //帶頭&#xff08;哨兵位&#xff09;下標為0 //單向&#xff0c;雙向&#xff0c;循環鏈表 //實現 單 //倆足夠大數組 // elem&#xff0c;數據域 // next &#xff0c;指針域…

《Computational principles and challenges in single-cell data integration》

1. 引言&#xff1a;單細胞數據整合的背景與重要性單細胞基因組學技術&#xff08;如scRNA-seq、scATAC-seq等&#xff09;近年來快速發展&#xff0c;能夠以單細胞分辨率揭示細胞異質性和分子機制。然而&#xff0c;不同實驗、樣本和數據模態&#xff08;如RNA表達、DNA甲基化…

蔚來汽車攜手通義靈碼入選 2025 世界人工智能大會標桿案例

7月28日&#xff0c;在2025年世界人工智能大會上&#xff0c;通義靈碼助力蔚來汽車研發效能升級成功入選2025年“人工智能”行業標桿案例薈萃。蔚來汽車已有近 1000 名工程師常態化使用通義靈碼&#xff0c;AI 生成代碼占比超 30%&#xff0c;尤其在蔚來“天探”AI自檢系統的建…

Spring Boot中的this::語法糖詳解

文章目錄前言什么是方法引用&#xff08;Method Reference&#xff09;基本語法方法引用的四種類型1. 靜態方法引用2. 實例方法引用&#xff08;特定對象&#xff09;3. 實例方法引用&#xff08;任意對象&#xff09;4. 構造器引用this::在Spring Boot中的應用場景1. Service層…

VitePress學習筆記

VitePress學習筆記VitePress學習搭建和運行編寫內容mdvue配置站點配置配置searchsearch 提示詞替換使用第三方主題自定義主題設置文檔根目錄國際化文檔navsidebarsearch其他插件vitepress插件markdown-it插件項目開發原始需求和方案自動化流程權限限制VitePress學習 搭建和運行…

C#_創建自己的MyList列表

定義一個數據自己的列表MyList 使用上述描述列表的方式(數組) 列表內也要定義屬于自己的方法 例如 Sort排序 Add添加 等等....思路┌─────────────────────────────────────────────────────────────────…

記錄Linux下ping外網失敗的問題

最近在RK3568上進行開發測試&#xff0c;需要測試一下網絡環境&#xff0c;能否通過瀏覽器訪問外部網絡。測試情況如下&#xff1a; 1、ping內網、網關ip能ping通 2、ping外網ping不通 情況分析&#xff1a; 1、ping外網失敗&#xff08;ping 8.8.8.8也ping不通&#xff0c;說…

Redis 鍵值對操作詳解:Python 實現指南

一、環境準備 1. 安裝依賴庫 pip install redis2. 連接 Redis 數據庫 import redis# 創建 Redis 客戶端連接 r redis.Redis(hostlocalhost, # Redis 服務器地址port6379, # Redis 端口db0, # 數據庫編號&#xff08;0~15&#xff09;passwordNone, …

制造業企業大文件傳輸的痛點有哪些?

在全球化與數字化的浪潮下&#xff0c;制造業企業的大文件傳輸需求日益凸顯&#xff0c;然而諸多痛點也隨之而來&#xff0c;嚴重制約著企業的高效運營與發展。復雜網絡環境導致傳輸穩定性差制造業企業常涉及跨地域、跨國的業務合作與數據交流&#xff0c;網絡環境復雜多變。在…