本篇內(nèi)容介紹了“Qt mpv通用接口怎么實現(xiàn)”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!
在博樂等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè) 網(wǎng)站設(shè)計制作定制網(wǎng)站開發(fā),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),全網(wǎng)營銷推廣,外貿(mào)網(wǎng)站建設(shè),博樂網(wǎng)站建設(shè)費用合理。
前面幾篇文章,依次講了解碼播放、錄像存儲、讀取和控制、事件訂閱等,其實這些功能的實現(xiàn)都離不開封裝的通用的接口,最開始本人去調(diào)用一些設(shè)置的時候,發(fā)現(xiàn)多參數(shù)的不好實現(xiàn),原來需要用mpv_node處理,而Qt中如何轉(zhuǎn)成mpv_node需要特殊的處理才行,后來在開源主頁看到了官方提供的demo例子,直接用qt封裝好了多個接口(https://github.com/mpv-player/mpv-examples/tree/master/libmpv),看里面的注釋是英文的,估計應(yīng)該是官方提供的,傳入的參數(shù)都是支持QVariant的,這樣兼容性就超級強大了,多種不同類型的數(shù)據(jù)參數(shù)都可以傳入進去,再次感謝官方的demo,官方的demo除了有QWidget的外還有qml的版本,同時還提供了opengl版本,各位有興趣都可以down下來看看,不過demo比較簡單就是,并沒有演示所有的功能,只演示了最基礎(chǔ)的功能比如播放視頻進度控制等,離一個完整的視頻播放器差十萬八千里不止。
主要接口如下:
通用獲取屬性接口函數(shù) get_property_variant
通用設(shè)置屬性接口函數(shù) set_property_variant
通用設(shè)置參數(shù)接口函數(shù) set_option_variant
通用執(zhí)行命令接口函數(shù) command_variant
多線程實時播放視頻流+本地視頻等。
支持windows+linux+mac。
多線程顯示圖像,不卡主界面。
自動重連網(wǎng)絡(luò)攝像頭。
可設(shè)置是否保存到文件以及文件名。
可直接拖曳文件到mpvwidget控件播放。
支持h365視頻流+rtmp等常見視頻流。
可暫停播放和繼續(xù)播放。
支持存儲單個視頻文件和定時存儲視頻文件。
自定義頂部懸浮條,發(fā)送單擊信號通知,可設(shè)置是否啟用。
可設(shè)置畫面拉伸填充或者等比例填充。
可對視頻進行截圖(原始圖片)和截屏。
錄像文件存儲MP4文件。
支持qsv、dxva2、d3d11va等硬解碼。
struct node_builder { node_builder(const QVariant &v) { set(&node_, v); } ~node_builder() { free_node(&node_); } mpv_node *node() { return &node_; } private: Q_DISABLE_COPY(node_builder) mpv_node node_; mpv_node_list *create_list(mpv_node *dst, bool is_map, int num) { dst->format = is_map ? MPV_FORMAT_NODE_MAP : MPV_FORMAT_NODE_ARRAY; mpv_node_list *list = new mpv_node_list(); dst->u.list = list; if (!list) { goto err; } list->values = new mpv_node[num](); if (!list->values) { goto err; } if (is_map) { list->keys = new char *[num](); if (!list->keys) { goto err; } } return list; err: free_node(dst); return NULL; } char *dup_qstring(const QString &s) { QByteArray b = s.toUtf8(); char *r = new char[b.size() + 1]; if (r) { std::memcpy(r, b.data(), b.size() + 1); } return r; } bool test_type(const QVariant &v, QMetaType::Type t) { // The Qt docs say: "Although this function is declared as returning // "QVariant::Type(obsolete), the return value should be interpreted // as QMetaType::Type." // So a cast really seems to be needed to avoid warnings (urgh). return static_cast(v.type()) == static_cast (t); } void set(mpv_node *dst, const QVariant &src) { if (test_type(src, QMetaType::QString)) { dst->format = MPV_FORMAT_STRING; dst->u.string = dup_qstring(src.toString()); if (!dst->u.string) { goto fail; } } else if (test_type(src, QMetaType::Bool)) { dst->format = MPV_FORMAT_FLAG; dst->u.flag = src.toBool() ? 1 : 0; } else if (test_type(src, QMetaType::Int) || test_type(src, QMetaType::LongLong) || test_type(src, QMetaType::UInt) || test_type(src, QMetaType::ULongLong)) { dst->format = MPV_FORMAT_INT64; dst->u.int64 = src.toLongLong(); } else if (test_type(src, QMetaType::Double)) { dst->format = MPV_FORMAT_DOUBLE; dst->u.double_ = src.toDouble(); } else if (src.canConvert ()) { QVariantList qlist = src.toList(); mpv_node_list *list = create_list(dst, false, qlist.size()); if (!list) { goto fail; } list->num = qlist.size(); for (int n = 0; n < qlist.size(); n++) { set(&list->values[n], qlist[n]); } } else if (src.canConvert ()) { QVariantMap qmap = src.toMap(); mpv_node_list *list = create_list(dst, true, qmap.size()); if (!list) { goto fail; } list->num = qmap.size(); for (int n = 0; n < qmap.size(); n++) { list->keys[n] = dup_qstring(qmap.keys()[n]); if (!list->keys[n]) { free_node(dst); goto fail; } set(&list->values[n], qmap.values()[n]); } } else { goto fail; } return; fail: dst->format = MPV_FORMAT_NONE; } void free_node(mpv_node *dst) { switch (dst->format) { case MPV_FORMAT_STRING: delete[] dst->u.string; break; case MPV_FORMAT_NODE_ARRAY: case MPV_FORMAT_NODE_MAP: { mpv_node_list *list = dst->u.list; if (list) { for (int n = 0; n < list->num; n++) { if (list->keys) { delete[] list->keys[n]; } if (list->values) { free_node(&list->values[n]); } } delete[] list->keys; delete[] list->values; } delete list; break; } default: ; } dst->format = MPV_FORMAT_NONE; } }; struct node_autofree { mpv_node *ptr; node_autofree(mpv_node *a_ptr) : ptr(a_ptr) {} ~node_autofree() { mpv_free_node_contents(ptr); } }; static inline QVariant get_property_variant(mpv_handle *ctx, const QString &name) { mpv_node node; if (mpv_get_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, &node) < 0) { return QVariant(); } node_autofree f(&node); return node_to_variant(&node); } static inline int set_property_variant(mpv_handle *ctx, const QString &name, const QVariant &v) { node_builder node(v); return mpv_set_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node()); } static inline int set_option_variant(mpv_handle *ctx, const QString &name, const QVariant &v) { node_builder node(v); return mpv_set_option(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node()); } static inline QVariant command_variant(mpv_handle *ctx, const QVariant &args) { node_builder node(args); mpv_node res; if (mpv_command_node(ctx, node.node(), &res) < 0) { return QVariant(); } node_autofree f(&res); return node_to_variant(&res); } static inline QVariant get_property(mpv_handle *ctx, const QString &name) { mpv_node node; int err = mpv_get_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, &node); if (err < 0) { return QVariant::fromValue(ErrorReturn(err)); } node_autofree f(&node); return node_to_variant(&node); } static inline int set_property(mpv_handle *ctx, const QString &name, const QVariant &v) { node_builder node(v); return mpv_set_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node()); }
“Qt mpv通用接口怎么實現(xiàn)”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!