cocos2dx跨平台直播实例-ffmpeg-ios篇

2023-11-18

一、环境

    mac 10.12.2

    cocos2dx-3.13.1

    ffmpeg 3.0

二、新建项目和编译库

    cocos2dx按照官网新建一个实例。

    ffmpeg编译ios库http://blog.csdn.net/u013654125/article/details/73549132

    ffmpeg编译完后,会有得到一个FFmpeg-iOS文件夹,文件夹里有include和lib这两个文件夹。这两个文件夹里就是ffmpeg编译好的头文件和库文件。

三、项目配置


如上图:

这三个地方需要做一些修改。

第一个方框的配置

LiveVideo.cpp

//
//  LiveVideo.cpp
//  Game
//
//  Created by zhufu on 2017/3/1.
//
//

#include "LiveVideo.h"
#include "HelloWorldScene.h"

#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif

extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/avutil.h"
#include "libavfilter/avfilter.h"
#endif
}

Scene* LiveVideo::createScene()
{
    auto scene = Scene::create();
    auto sprite = Sprite::create("HelloWorld.png");
    
    
    // position the sprite on the center of the screen
    sprite->setPosition(Vec2(Director::getInstance()->getVisibleSize().width/2-140, Director::getInstance()->getVisibleSize().height/2+100));
    
    // add the sprite as a child to this layer
    scene->addChild(sprite, 0);
    LiveVideo* liveVideo = LiveVideo::create();
    scene->addChild(liveVideo);
    liveVideo->init();
    auto layer = HelloWorld::create();
    scene->addChild(layer);
    return scene;
}

LiveVideo* LiveVideo::create()
{
    LiveVideo* liveVideo = new(std::nothrow) LiveVideo();
    if(liveVideo)
    {
        liveVideo->autorelease();
        return liveVideo;
    }
    CC_SAFE_DELETE(liveVideo);
    return nullptr;
}

bool LiveVideo::init()
{
    initEvents();
    initCommand();
    //ffmpeg解码线程
    play();
    
    addPlayButton();
    addPlayHKSButton();
    addStopButton();
    addRefreshButton();
    
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    loadShader();
    loadTexture();
    loadRectangle();
    return true;
}

void LiveVideo::addPlayButton()
{
    auto button = ui::Button::create("CloseNormal.png", "CloseSelected.png");
    button->setTitleText("play");
    button->setPosition(Vec2(170, 100));
    button->addClickEventListener(CC_CALLBACK_0(LiveVideo::play, this));
    button->setContentSize(Size(100, 100));
    addChild(button);
}

void LiveVideo::addPlayHKSButton()
{
    auto button = ui::Button::create("CloseNormal.png", "CloseSelected.png");
    button->setTitleText("playHKS");
    button->setPosition(Vec2(240, 100));
    button->addClickEventListener(CC_CALLBACK_0(LiveVideo::playHKS, this));
    button->setContentSize(Size(100, 100));
    addChild(button);
}

void LiveVideo::addStopButton()
{
    auto button = ui::Button::create("CloseNormal.png", "CloseSelected.png");
    button->setTitleText("stop");
    button->setPosition(Vec2(170, 50));
    button->addClickEventListener(CC_CALLBACK_0(LiveVideo::stop, this));
    button->setContentSize(Size(100, 100));
    addChild(button);
}

void LiveVideo::addRefreshButton()
{
    auto button = ui::Button::create("CloseNormal.png", "CloseSelected.png");
    button->setTitleText("refresh");
    button->setPosition(Vec2(240, 50));
    button->addClickEventListener(CC_CALLBACK_0(LiveVideo::refresh, this));
    button->setContentSize(Size(100, 100));
    addChild(button);
}

void LiveVideo::initEvents()
{
    EventListenerCustom* stopDecodeListener = EventListenerCustom::create("stopFFmpegDecode", CC_CALLBACK_0(LiveVideo::stop, this));
    Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(stopDecodeListener, 1);
    
    EventListenerCustom* startDecodeListener = EventListenerCustom::create("startFFmpegDecode", CC_CALLBACK_0(LiveVideo::ffmpegDecode, this, currentLivePath));
    Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(startDecodeListener, 1);
}

void LiveVideo::play()
{
    if(!isPlay())
    {
        const char* filePath = "rtmp://113.10.194.251/live/mtable1";
        setPlay(true);
        std::thread t(&LiveVideo::ffmpegDecode, this, filePath);
        t.detach();
        
    }
    
}

void LiveVideo::playHKS()
{
    if(!isPlay())
    {
        const char* filePath ="rtmp://live.hkstv.hk.lxdns.com/live/hks";
        setPlay(true);
        std::thread t(&LiveVideo::ffmpegDecode, this, filePath);
        t.detach();
        
    }
    
}

void LiveVideo::stop()
{
    setPlay(false);
}

void LiveVideo::refresh()
{
    if(_playFlag)
    {
        clearBuf();
    } else {
        play();
    }
    
}

void LiveVideo::setPlay(bool playFlag)
{
    _playFlag = playFlag;
}

bool LiveVideo::isPlay()
{
    return _playFlag;
}

long LiveVideo::getCurrentTime()
{
    struct timeval now;
    gettimeofday(&now, NULL);
    return now.tv_sec*1000 +  (int)(now.tv_usec/1000+0.5);
}

void LiveVideo::flipVertical(int width, int height, char* arr)
{
    int index = 0, f_index, cycle=height>>1;
    char buf;
    for (int i = 0; i < cycle; i++)
    {
        for (int j = 0; j < width; j++)
        {
            //当前像素
            index = i*width + j;
            //需要交换的像素
            f_index = (height - 1 - i)*width + j;
            //缓存当前像素
            buf = arr[index];
            //交换像素
            arr[index] = arr[f_index];
            //交换回像素
            arr[f_index] = buf;
        }
    }
}

int LiveVideo::ffmpegDecode(const char* filePath)
{
    //开始解码
    CCLOG("filePath %s", filePath);
//    strcpy(currentLivePath, filePath);
    av_register_all();
    avformat_network_init();
    AVFormatContext* pFormat = NULL;
    AVCodecContext* video_dec_ctx = NULL;
    AVCodec* video_dec = NULL;
    AVPacket *pkt = NULL;
    AVFrame *pFrame = NULL;
    
    do {
        
        if (avformat_open_input(&pFormat, filePath, NULL, NULL) < 0)
        {
            CCLOG("Couldn't open input stream.(无法打开输入流)\n");
            break;
        }
        
        CCLOG("%lld", pFormat->probesize);
        CCLOG("%lld", pFormat->max_analyze_duration);
        pFormat->probesize = 100;
        pFormat->max_analyze_duration = 0;
        if (avformat_find_stream_info(pFormat, NULL) < 0)
        {
            CCLOG("Couldn't find stream information.(无法获取流信息)\n");
            break;
        }
        
        int i, videoIndex=-1;
        for(i = 0; i<pFormat->nb_streams; i++)
        {
            if(pFormat->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
            {
                videoIndex=i;
                break;
            }
        }
        if(videoIndex==-1)
        {
            printf("Didn't find a video stream.(没有找到视频流)\n");
            break;
        }
        video_dec_ctx=pFormat->streams[videoIndex]->codec;
        _frameRate = pFormat->streams[videoIndex]->r_frame_rate.num;
        if(_frameRate == 0)
        {
            _frameRate = 1;
        }
        
        _system_start_time = getCurrentTime();
        _start_time = pFormat->streams[videoIndex]->start_time;
        
        _pixel_w = video_dec_ctx->width;
        _pixel_h = video_dec_ctx->height;
        int pixel_w2 = _pixel_w >> 1;
        int pixel_h2 = _pixel_h >> 1;
        video_dec=avcodec_find_decoder(video_dec_ctx->codec_id);
        if(video_dec==NULL)
        {
            printf("Codec not found.(没有找到解码器)\n");
            break;
        }
        if(avcodec_open2(video_dec_ctx, video_dec,NULL)<0)
        {
            printf("Could not open codec.(无法打开解码器)\n");
            break;
        }
        
        
        pkt = av_packet_alloc();
        av_init_packet(pkt);
        pFrame = av_frame_alloc();
    
    
        while (_playFlag)
        {
            if(av_read_frame(pFormat, pkt) < 0)
            {
                CCLOG("读取帧失败!!!!");
                break;
            }
            if (pkt->stream_index == videoIndex)
            {
                int got_picture = 0,ret = 0;
                ret = avcodec_decode_video2(video_dec_ctx, pFrame, &got_picture, pkt);
                if (ret < 0)
                {
                    printf("Decode Error.(解码错误)\n");
                    break;
                }
                if (got_picture)
                {
                    char* buf = new char[video_dec_ctx->height * video_dec_ctx->width * 3 / 2];
                    int a = 0, i;
                    for (i = 0; i<_pixel_h; i++)
                    {
                        memcpy(buf + a, pFrame->data[0] + i * pFrame->linesize[0], _pixel_w);
                        a += _pixel_w;
                    }
                    flipVertical(_pixel_w, _pixel_h, buf);
                    for (i = 0; i<pixel_h2; i++)
                    {
                        memcpy(buf + a, pFrame->data[1] + i * pFrame->linesize[1], pixel_w2);
                        a += pixel_w2;
                    }
                    flipVertical(pixel_w2, pixel_h2, buf+_pixel_w*_pixel_h);
                    for (i = 0; i<pixel_h2; i++)
                    {
                        memcpy(buf + a, pFrame->data[2] + i * pFrame->linesize[2], pixel_w2);
                        a += pixel_w2;
                    }
                    flipVertical(pixel_w2, pixel_h2, buf+_pixel_w*_pixel_h+_pixel_w*_pixel_h/4);
                    FrameData data;
                    data.pts = pFrame->pkt_pts;
                    data.buf = buf;
                    
                    _data.push_back(data);
                    buf = NULL;
                    
                    CCLOG("pts %lld", pkt->pts);
                    CCLOG("pts %lld", pFrame->pts);
                    AVRational test;
                    test = av_get_time_base_q();
                    CCLOG("test %d, %d", test.num, test.den);
                }
            }
            
            av_packet_unref(pkt);
        }
    } while (0);
    
    _playFlag = false;
    clearBuf();
    if(pFrame)
    {
        av_frame_free(&pFrame);
        av_free(pFrame);
        delete pFrame;
        pFrame = NULL;
    }
    
    if(pkt)
    {
        av_packet_free_side_data(pkt);
        av_packet_unref(pkt);
        av_packet_free(&pkt);
    }
    
    if(video_dec_ctx)
    {
        avcodec_close(video_dec_ctx);
        video_dec_ctx = NULL;
    }
    
    if(pFormat)
    {
        avformat_close_input(&pFormat);
        avformat_free_context(pFormat);
        delete pFormat;
        pFormat = NULL;
    }
    
    return 0;
}

void LiveVideo::clearBuf()
{
    std::vector<FrameData>::iterator it;
    for(it = _data.begin(); it != _data.end(); )
    {
        if(it->buf)
        {
            delete[] it->buf;
            it->buf = NULL;
        }
        it = _data.erase(it);
    }
}

void LiveVideo::loadShader()
{
    _glProgram = new GLProgram();
    _glProgram->initWithFilenames("shader/vertexShader.vsh", "shader/fragmentShader.fsh");
    _glProgram->link();
}

void LiveVideo::loadTexture()
{
    glGenTextures(1, &_textureY);
    glBindTexture(GL_TEXTURE_2D, _textureY);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    glGenTextures(1, &_textureU);
    glBindTexture(GL_TEXTURE_2D, _textureU);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    glGenTextures(1, &_textureV);
    glBindTexture(GL_TEXTURE_2D, _textureV);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}

void LiveVideo::loadRectangle()
{
    //创建vao
    glGenVertexArrays(1, &_gVAO);
    glBindVertexArray(_gVAO);
    
    //创建vbo
    glGenBuffers(1, &_gVBO);
    glBindBuffer(GL_ARRAY_BUFFER, _gVBO);
    
    //创建顶点数组
    GLfloat vertex[] = {
        //  X     Y     Z       U     V
        -1.0f, 1.0f, 0.0f,   0.0f, 1.0f,
        1.0f, 1.0f, 0.0f,   1.0f, 1.0f,
        -1.0f, -1.0f, 0.0f,   0.0f, 0.0f,
        1.0f, -1.0f, 0.0f,   1.0f, 0.0f,
    };
    
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW);
    
    //绑定数据到vertexIn
    glEnableVertexAttribArray(_glProgram->getAttribLocation("vertexIn"));
    glVertexAttribPointer(_glProgram->getAttribLocation("vertexIn"), 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), NULL);
    
    //绑定数据到textureIn
    glEnableVertexAttribArray(_glProgram->getAttribLocation("textureIn"));
    glVertexAttribPointer(_glProgram->getAttribLocation("textureIn"), 2, GL_FLOAT, GL_TRUE, 5 * sizeof(GLfloat), (const GLvoid*)(3 * sizeof(GLfloat)));
    
    //unbind the VAO
    glBindVertexArray(0);
}

void LiveVideo::initCommand()
{
    _command.init(_globalZOrder);
    _command.func = CC_CALLBACK_0(LiveVideo::onDraw, this);
}

void LiveVideo::draw(Renderer *render, const Mat4 &transform, uint32_t flags)
{
    
    onDraw();
}

void LiveVideo::onDraw()
{
    now = getCurrentTime();
    
    char* buf = getBuff();
    
    
    if(buf ==NULL)
    {
        return;
    }
    // clear everything
    glClearColor(0, 0, 0, 1); // black
    glClear(GL_COLOR_BUFFER_BIT);
    
    // bind the program (the shaders)
    _glProgram->use();
    
    /**
     * 为了直播临时添加的bindLiveVideoTexture2DN
     */
    GL::bindLiveVideoTexture2DN(0, _textureY);
    glTexImage2D(GL_TEXTURE_2D,
                 0,
                 0x1903,
                 _pixel_w,
                 _pixel_h,
                 0,
                 0x1903,
                 GL_UNSIGNED_BYTE,
                 buf);
    GLuint p =  glGetUniformLocation(_glProgram->getProgram(), "tex_y");
    glUniform1i(p, 0);
    
    
    GL::bindLiveVideoTexture2DN(1, _textureU);
    glTexImage2D(GL_TEXTURE_2D,
                 0,
                 0x1903,
                 _pixel_w/2,
                 _pixel_h/2,
                 0,
                 0x1903,
                 GL_UNSIGNED_BYTE,
                 buf + _pixel_w*_pixel_h);
    GLuint p1 =  glGetUniformLocation(_glProgram->getProgram(), "tex_u");
    glUniform1i(p1, 1);
    
    
    GL::bindLiveVideoTexture2DN(2, _textureV);
    glTexImage2D(GL_TEXTURE_2D,
                 0,
                 0x1903,
                 _pixel_w/2,
                 _pixel_h/2,
                 0,
                 0x1903,
                 GL_UNSIGNED_BYTE,
                 buf + _pixel_w*_pixel_h + _pixel_w*_pixel_h/4);
    GLuint p2 =  glGetUniformLocation(_glProgram->getProgram(), "tex_v");
    glUniform1i(p2, 2);
    
    
    buf = NULL;
    
    //    glProgram->setUniform("tex", 0); //set to 0 because the texture is bound to GL_TEXTURE0
    
    // bind the VAO (the triangle)
    glBindVertexArray(_gVAO);
    
    // draw the VAO
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    // unbind the VAO, the program and the texture
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);
    glUseProgram(0);
}

char* LiveVideo::getBuff()
{
    char* buf = NULL;
    std::vector<FrameData>::iterator it;
    std::vector<FrameData>::iterator temp;
    for(it = _data.begin(); it != _data.end(); )
    {
        for(temp = _data.begin(); temp != _data.end();)
        {
            if(temp != it && temp->buf == it->buf)
            {
                CCLOG("~!!!有两个指针指向同一个地址");
                temp = _data.erase(temp);
            } else {
                ++temp;
            }
        }
        
        
        if(getDifferTime(it) < 0 && _data.size() > 1)
        {
            if(it->buf)
            {
                delete[] it->buf;
                it->buf = NULL;
            }
            it = _data.erase(it);
        }
        else
        {
            buf = it->buf;
            ++it;
            break;
        }
    }
    return buf;
}

long LiveVideo::getDifferTime(std::vector<FrameData>::iterator it)
{
    
    int64_t differTime = (it->pts - _start_time) - (now - _system_start_time);
    
    
    if(_data.size() > 40)
    {
        
        if(_data.size() <= 60)
        {
            if(_system_start_time > now - (_data.at(_data.size() - 25).pts - _start_time))
            {
                _system_start_time -= 20;
            }
            differTime = (it->pts - _start_time) - (now - _system_start_time + (_data.size()- 30)*20);
        }
        if(_data.size() > 60)
        {
            if(_system_start_time > now - (_data.at(_data.size() - 25).pts - _start_time))
            {
                _system_start_time -= 40;
            }
            differTime = (it->pts - _start_time) - (now - _system_start_time + (_data.size()- 30)*40);
        }
        
    }
    if(_data.size() > 30 && _data.size() <= 40)
    {
        differTime = (it->pts - _start_time) - (now - _system_start_time + (_data.size()- 30)*2);
    }
    
    if(_data.size() <= 15)
    {
        if(_system_start_time < now - (_data.begin()->pts - _start_time))
        {
            _system_start_time += 10;
        }
        differTime = (it->pts - _start_time) - (now - _system_start_time + (_data.size() - 15)*40);
    }
    return differTime;
}




LiveVideo.h

//
//  LiveVideo.h
//  Game
//
//  Created by zhufu on 2017/3/1.
//
//

#ifndef LiveVideo_h
#define LiveVideo_h

#include <stdio.h>
#include "ui/cocosGUI.h"

USING_NS_CC;

#endif /* LiveVideo_h */
class LiveVideo : public Node
{
private:
    struct FrameData {
        int64_t pts;
        char* buf;
    };
public:
    static Scene* createScene();
    static LiveVideo* create();
    virtual bool init() override;
    void initEvents();
    int ffmpegDecode(const char* filePath);
    void flipVertical(int width, int height, char* arr);
    
    virtual void draw(Renderer* renderer, const Mat4 &transform, uint32_t flags) override;
    
    void loadShader();
    void loadTexture();
    void loadRectangle();
    void onDraw();
    void initCommand();
    long getCurrentTime();
    long getDifferTime(std::vector<FrameData>::iterator it);
    char* getBuff();
    
    void addPlayButton();
    void addPlayHKSButton();
    void addStopButton();
    void addRefreshButton();
    
    void play();
    void playHKS();
    void stop();
    void refresh();
    
    void setPlay(bool playFlag);
    bool isPlay();
    
    void clearBuf();
private:
    CustomCommand _command;
    GLProgram* _glProgram;
    bool _playFlag = false;
    GLuint _textureY;
    GLuint _textureU;
    GLuint _textureV;
    GLuint _gVAO = 0;
    GLuint _gVBO = 0;
    int _pixel_w = 320, _pixel_h = 180;
    
    std::vector<FrameData> _data;
    int _frameRate;
    
    int64_t _start_time;
    long _system_start_time;
    char* currentLivePath = new char[256];
    
    long now;
};

之后,再在AppDelegate.cpp里引用LiveVideo.h文件:


第二个框的配置:

fragmentShader.fsh

varying vec2 textureOut;
uniform sampler2D tex_y;
uniform sampler2D tex_u;
uniform sampler2D tex_v;
void main(void)
{
    vec3 yuv;
    vec3 rgb;
    yuv.x = texture2D(tex_y, textureOut).r;
    yuv.y = texture2D(tex_u, textureOut).r - 0.5;
    yuv.z = texture2D(tex_v, textureOut).r - 0.5;
    rgb = mat3( 1,       1,         1,
               0,       -0.39465,  2.03211,
               1.13983, -0.58060,  0) * yuv;
    gl_FragColor = vec4(rgb, 1);
}

vertexShader.vsh

attribute vec3 vertexIn;
attribute vec2 textureIn;
varying vec2 textureOut;
void main(void)
{
    gl_Position = vec4(vertexIn, 1);
    textureOut = textureIn;
}

右击Resources,出现如图:


点击"Add Files to "Game",出现如图:


选择fshader文件夹,再点Add,完成第二个框的配置。

每三个框的配置:

把开始编译好的FFmpeg-iOS文件夹复制到如图路径:


再:


选择FFmpeg-iOS文件夹加入到项目中:


。。。。。

完成配置,运行。。。。。

最后,大家如果配置的时候出现问题可以留言或者直接下载项目https://github.com/zhu12345618/ffmpeg_ios_Test

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cocos2dx跨平台直播实例-ffmpeg-ios篇 的相关文章

随机推荐

  • eNSP:VLAN相关实验

    一 实验要求 二 实验步骤 1 建立拓扑 2 创建并配置VLAN 2 将交换机上各个接口划分到对应的vlan中 3 配置Trunk干道 4 配置单臂路由 路由器子接口 5 设置所有PC端为DHCP 6 测试
  • 为支撑小程序接口,配置https

    1 从阿里云购买免费的ssl证书 博主太穷 买不起付费的 https common buy aliyun com spm 5176 7968328 1290860 26 59b61232sjkAJj commodityCode cas re
  • Nginx(六)Nginx请求处理机制

    转载自 本文为您解读 Nginx是如何处理请求的 让你从逻辑上有一个清晰的认识 1 处理什么样的请求 处理访问到 Nginx 所在 IP 地址的请求 并且这些请求的 HTTP 头信息中的 Host 为所要处理的域名 如下以80端口为例 如下
  • zabbix使用Omsa来监控Dell服务器的硬件信息

    OMSA介绍 Dell OpenManage Server Administrator OMSA 是一款全面的一对一系统管理解决方案 OMSA可分为两种 集成式界面 基于Web浏览器的图形用户界面 GUI 命令行界面 CLI 通过操作系统访
  • java中如何通过JDBC的方式连接sqlserver2005多实例数据库?

    java语言中 通过jdbc访问sqlserver2005数据库默认实例可以按正常的写法来建立url连接 代码如下 Connection cn DriverManager getConnection jdbc sqlserver 172 1
  • docker安装mongodb提示bash: mongo: command not found

    docker安装MongoDB容器 docker run d p 27017 27017 name mongodb e MONGO INITDB ROOT USERNAME admin e MONGO INITDB ROOT PASSWOR
  • 嵌入式数据库——sqlite3

    前言 数据库是 按照数据结构来组织 存储和管理数据的仓库 是一个长期存储在计算机内的 有组织的 可共享的 统一管理的大量数据的集合 数据库是以一定方式储存在一起 能与多个用户共享 具有尽可能小的冗余度 与应用程序彼此独立的数据集合 可视为电
  • DataGridView实现添加合计行并始终显示在底部

    DataGridView中没有合适的方法来冻结底部的合计行 这里用一种比较简单的方式实现 1 数据部分的DataGridView 不带任何滚动框2 合计部分的DataGridView 带有横向滚动框3 在画面上添加一个纵向滚动框实现的主要思
  • python爬虫网络出错怎么办_python爬虫之headers处理、网络超时问题处理

    1 请求headers处理 我们有时请求服务器时 无论get或post请求 会出现403错误 这是因为服务器拒绝了你的访问 这时我们可以通过模拟浏览器的头部信息进行访问 这样就可以解决反爬设置的问题 importrequests 创建需要爬
  • Rxjava+Retrofit嵌套处理请求,并优雅的处理异常

    前情提示 本文只是一个例子 不做过多讲解 入门知识推荐参考 仍物线大神讲解的Rxjava 如何优雅的处理服务器异常 本文没有对Rxjava进行任何封装 也没有使用retrolambda 因为对于初学者来说 看起来费 不 劲 会 而且也没必要
  • 跳转页面保存输入的信息到url上,Js现实

    Js现实 获取用户点击岗位的次数 params act add id info bx id click num click num 获取岗位选中的值 params params auth role id now id 拼接其他数据 var
  • spring源码--04--IOC原理--XmlBeanFactory(IOC容器)的初始化(不细)

    XmlBeanFactory IOC容器 的初始化 不细 1 验证过程 代码地址 https gitee com DanShenGuiZu learnDemo tree master spring源码学习 spring source lea
  • 【LeetCode专题】二分答案

    本人参考yxc y总的刷题课 总结了二分查找的两个模板 HERE 本专题为二分查找算法的应用 二分答案 目录 LeetCode 875 爱吃香蕉的珂珂 LeetCode 2187 完成旅途的最少时间 LeetCode 6325 修车的最少时
  • unity识别图片颜色并把颜色数量排序

    首先把图片放入工程 拖入组件中 运行就可以看到颜色 这些颜色都是经过排序的 颜色最多的在最前面 视频 源码
  • Linux虚拟机启用时,出现:‘VMware虚拟机中出现无法将(系统文件路径)文件当做CD-ROM映像进行连接。

    启用Linux时 出现如下错误 解决方法 请先关闭虚拟 不然无法选择文件路径 第一步 点击CD DVD IDE 查看所在文件路径是否正确 第二步 选择启动时连接 选择自己所使用的ISO影像文件 M 修改到自己所在的路径 然后重启虚拟机 即可
  • MySQL数据库 之 插入、更新与删除数据

    欢迎大家扫码关注我的微信公众号 一 插入数据 MySQL 中使用 insert 语句来向数据库表中插入新的数据记录 为表的所有字段插入数据 insert into tb name col list values value list 创建一
  • 蓝桥杯-排列序数

    题目 标题 排列序数 如果用a b c d这4个字母组成一个串 有4 24种 如果把它们排个序 每个串都对应一个序号 abcd 0 abdc 1 acbd 2 acdb 3 adbc 4 adcb 5 bacd 6 badc 7 bcad
  • 关于HFile的存储结构梳理以及快速定位rowkey

    为什么80 的码农都做不了架构师 gt gt gt 一 HFile结构介绍 为了支持数据的随机查询 HFile结构分为六个部分 1 数据块 保存表中的数据 每一个数据块由块头和一些keyValue record 组成 key的值是严格按照顺
  • Ubuntu18.04安装CUDA11.3和cuDNN8.2.0

    今天在服务器上跑代码 发现报错 说是CUDA版本不对 然后看了一下服务器的版本 发现是9 0 这就有问题了啊 3090的显卡得用11 0上的版本啊 所以接着配置一下深度学的环境 记录一下方便以后查阅 Ubuntu18 04安装CUDA11
  • cocos2dx跨平台直播实例-ffmpeg-ios篇

    一 环境 mac 10 12 2 cocos2dx 3 13 1 ffmpeg 3 0 二 新建项目和编译库 cocos2dx按照官网新建一个实例 ffmpeg编译ios库http blog csdn net u013654125 arti