zoukankan      html  css  js  c++  java
  • 字符动画播放器,不止BadApple!

    思路

    libvlc解码转码出RGBA和播放音频,再将RGBA量化为黑('*')白(' ')两个颜色并输出到屏幕。

    效果视频

    https://www.bilibili.com/video/BV1N64y1u7BD

    代码仓库

    https://github.com/gongluck/Character-player/tree/console

    #include <iostream>
    #include <thread>
    #include <atomic>
    
    #ifdef _WIN32
    #include <Windows.h>
    #define ssize_t SSIZE_T
    #endif
    #include <vlc/vlc.h>
    
    #define CHECKEQUALRET(ret, compare)
    if(ret == compare)
    {
        std::cerr << "error ocurred in " << __FILE__
                  << "`s line " << __LINE__
                  << ", error " << ret;
        goto END;
    }
    
    #define CHECKNEQUALRET(ret, compare)
    if(ret != compare)
    {
        std::cerr << "error ocurred in " << __FILE__
                  << "`s line " << __LINE__
                  << ", error " << ret;
        goto END;
    }
    
    static int WIDTH = 200;
    static int HEIGHT = 50;
    static char* out_buffer = nullptr;
    static char* tmp_buffer = nullptr;
    static char* print_buffer = nullptr;
    std::atomic<bool> atomiclock;
    std::atomic<bool> gotframe = false;
    static void* lock(void* data, void** p_pixels)
    {
        while (atomiclock)
        {
            std::this_thread::sleep_for(std::chrono::microseconds(10));
        }
        atomiclock = true;
        *p_pixels = out_buffer;
        return 0;
    }
    static void unlock(void* data, void* id, void* const* p_pixels)
    {
        atomiclock = false;
        gotframe = true;
    }
    static void display(/*void* data, void* id*/)
    {
        atomiclock = true;
        if (!gotframe)
        {
            atomiclock = false;
            std::this_thread::sleep_for(std::chrono::microseconds(10));
            return;
        }
        memcpy(tmp_buffer, out_buffer, HEIGHT * WIDTH * 4);
        gotframe = false;
        atomiclock = false;
    
        HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD pos = { 0 };
        SetConsoleCursorPosition(hConsoleOutput, pos);
    
        RGBQUAD* rgba = reinterpret_cast<RGBQUAD*>(tmp_buffer);
        for (int i = 0; i < HEIGHT; ++i)
        {
            for (int j = 0; j < WIDTH; ++j)
            {
                auto point = rgba[WIDTH * i + j];
                auto light = (point.rgbRed + point.rgbGreen + point.rgbBlue) / 3;
                print_buffer[i * (WIDTH + 2) + j] = light > 127 ? '*' : ' ';
            }
            print_buffer[i * (WIDTH + 2) + WIDTH] = '
    ';
            print_buffer[i * (WIDTH + 2) + WIDTH + 1] = '
    ';
        }
        puts(print_buffer);
    }
    
    int main(int argc, char** argv)
    {
        libvlc_instance_t* inst_ = nullptr;
        libvlc_media_t* media_ = nullptr;
        libvlc_media_player_t* player_ = nullptr;
        libvlc_media_list_t* list_ = nullptr;
        libvlc_media_list_player_t* plist_ = nullptr;
        int ret = 0;
    
        std::cout << "Usage: Character-player [media file] [out width] [out height]" << std::endl;
    
        if (argc >= 4)
        {
            WIDTH = atoi(argv[2]);
            HEIGHT = atoi(argv[3]);
        }
    
        HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD size = { WIDTH + 4, HEIGHT + 5 };
        SetConsoleScreenBufferSize(hConsoleOutput, size);
        SMALL_RECT rc = { 0,0, WIDTH + 1, HEIGHT + 1 };
        SetConsoleWindowInfo(hConsoleOutput, true, &rc);
    
        libvlc_log_close(nullptr);
    
        bool exit = false;
        std::thread th([&]()
        {
            while (!exit)
            {
                while (atomiclock)
                {
                    std::this_thread::sleep_for(std::chrono::microseconds(10));
                }
                display();
            }
        });
    
        inst_ = libvlc_new(0, nullptr);
        CHECKEQUALRET(inst_, nullptr);
        media_ = libvlc_media_new_path(inst_, argc <= 1 ? "badapple.mp4" : argv[1]);
        CHECKEQUALRET(media_, nullptr);
    
        out_buffer = static_cast<char*>(malloc(HEIGHT * WIDTH * 4));
        CHECKEQUALRET(out_buffer, nullptr);
        tmp_buffer = static_cast<char*>(malloc(HEIGHT * WIDTH * 4));
        CHECKEQUALRET(tmp_buffer, nullptr);
        print_buffer = static_cast<char*>(malloc(HEIGHT * (WIDTH + 2) + 1));
        CHECKEQUALRET(print_buffer, nullptr);
        print_buffer[HEIGHT * (WIDTH + 2)] = '';
    
        //player_ = libvlc_media_player_new_from_media(media_);
        player_ = libvlc_media_player_new(inst_);
        CHECKEQUALRET(player_, nullptr);
    
        libvlc_video_set_callbacks(player_, lock, unlock, nullptr, 0);
        libvlc_video_set_format(player_, "RGBA", WIDTH, HEIGHT, WIDTH * 4);
        //libvlc_media_player_set_hwnd(player_, GetDesktopWindow());
        
        // play loop
        list_ = libvlc_media_list_new(inst_);
        plist_ = libvlc_media_list_player_new(inst_);
        libvlc_media_list_add_media(list_, media_);
        libvlc_media_list_player_set_media_list(plist_, list_);
        libvlc_media_list_player_set_media_player(plist_, player_);
        libvlc_media_list_player_set_playback_mode(plist_, libvlc_playback_mode_loop);
        libvlc_media_list_player_play(plist_);
    
        std::cin.get();
    
    END:
        exit = true;
        if (th.joinable())
        {
            th.join();
        }
    
        if (player_ != nullptr)
        {
            libvlc_media_player_stop(player_);
            libvlc_media_player_release(player_);
            player_ = nullptr;
        }
        if (media_ != nullptr)
        {
            libvlc_media_release(media_);
            media_ = nullptr;
        }
    
        if (plist_ != nullptr)
        {
            libvlc_media_list_player_release(plist_);
            plist_ = nullptr;
        }
        if (list_ != nullptr)
        {
            libvlc_media_list_release(list_);
            list_ = nullptr;
        }
        if (inst_ != nullptr)
        {
            libvlc_release(inst_);
            inst_ = nullptr;
        }
    
        if (print_buffer != nullptr)
        {
            free(print_buffer);
            print_buffer = nullptr;
        }
        if (out_buffer != nullptr)
        {
            free(out_buffer);
            out_buffer = nullptr;
        }
        if (tmp_buffer != nullptr)
        {
            free(tmp_buffer);
            tmp_buffer = nullptr;
        }
    }
    
  • 相关阅读:
    技术选型总结
    这些年来收集的好用的好玩的软件,强烈推荐给大家
    如何解决markdown中图片上传的问题
    01.如何把.py文件打包成为exe,重点讲解pyinstaller的用法
    Asp.net中汉字转换成为拼音
    程序员常用网址收集
    通过IP来判断所在城市
    以太坊
    分布式系统领域经典论文翻译集
    T50
  • 原文地址:https://www.cnblogs.com/gongluck/p/12637021.html
Copyright © 2011-2022 走看看