前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >字符动画播放器,不止BadApple!

字符动画播放器,不止BadApple!

作者头像
gongluck
发布2020-04-08 15:55:43
6170
发布2020-04-08 15:55:43
举报
文章被收录于专栏:C++C++

思路

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

效果视频

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

代码仓库

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

代码语言:javascript
复制
#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] = '\r';
        print_buffer[i * (WIDTH + 2) + WIDTH + 1] = '\n';
    }
    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)] = '\0';

    //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;
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-05 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 思路
  • 效果视频
  • 代码仓库
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档