test_player.cpp 5.23 KB
Newer Older
1
/*
xiongziliang committed
2
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
xiongziliang committed
3 4 5
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
xiongziliang committed
6 7 8
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
xiongziliang committed
9
 */
xiongziliang committed
10

xzl committed
11
#include <signal.h>
12
#include "Util/util.h"
xzl committed
13 14 15
#include "Util/logger.h"
#include <iostream>
#include "Rtsp/UDPServer.h"
xiongziliang committed
16
#include "Player/MediaPlayer.h"
xzl committed
17
#include "Util/onceToken.h"
xiongziliang committed
18
#include "FFMpegDecoder.h"
xzl committed
19
#include "YuvDisplayer.h"
xiongziliang committed
20
#include "Extension/H265.h"
xzl committed
21 22

using namespace std;
xiongziliang committed
23 24
using namespace toolkit;
using namespace mediakit;
xzl committed
25

26

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/**
 * 合并一些时间戳相同的frame
 */
class FrameMerger {
public:
    FrameMerger() = default;
    virtual ~FrameMerger() = default;

    void inputFrame(const Frame::Ptr &frame,const function<void(uint32_t dts,uint32_t pts,const Buffer::Ptr &buffer)> &cb){
        if (!_frameCached.empty() && _frameCached.back()->dts() != frame->dts()) {
            Frame::Ptr back = _frameCached.back();
            Buffer::Ptr merged_frame = back;
            if(_frameCached.size() != 1){
                string merged;
                _frameCached.for_each([&](const Frame::Ptr &frame){
                    if(frame->prefixSize()){
                        merged.append(frame->data(),frame->size());
                    } else{
                        merged.append("\x00\x00\x00\x01",4);
                        merged.append(frame->data(),frame->size());
                    }
                });
                merged_frame = std::make_shared<BufferString>(std::move(merged));
            }
            cb(back->dts(),back->pts(),merged_frame);
            _frameCached.clear();
        }
        _frameCached.emplace_back(Frame::getCacheAbleFrame(frame));
    }
private:
    List<Frame::Ptr> _frameCached;
};


61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
#ifdef WIN32
#include <TCHAR.h>

extern int __argc;
extern TCHAR** __targv;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstanc, LPSTR lpCmdLine, int nShowCmd) {
    int argc = __argc;
    char **argv = __targv;

    //1. 首先调用AllocConsole创建一个控制台窗口
    AllocConsole();

    //2. 但此时调用cout或者printf都不能正常输出文字到窗口(包括输入流cin和scanf), 所以需要如下重定向输入输出流:
    FILE* stream;
    freopen_s(&stream, "CON", "r", stdin);//重定向输入流
    freopen_s(&stream, "CON", "w", stdout);//重定向输入流

    //3. 如果我们需要用到控制台窗口句柄,可以调用FindWindow取得:
    HWND _consoleHwnd;
    SetConsoleTitleA("test_player");//设置窗口名
#else
#include <unistd.h>
xiongziliang committed
84
int main(int argc, char *argv[]) {
85 86 87

#endif

xiongziliang committed
88
    static char *url = argv[1];
xiongziliang committed
89
    //设置退出信号处理函数
xiongziliang committed
90
    signal(SIGINT, [](int) { SDLDisplayerHelper::Instance().shutdown(); });
xiongziliang committed
91
    //设置日志
92
    Logger::Instance().add(std::make_shared<ConsoleChannel>());
93
    Logger::Instance().setWriter(std::make_shared<AsyncLogWriter>());
xzl committed
94

xiongziliang committed
95 96 97 98 99
    if (argc != 3) {
        ErrorL << "\r\n测试方法:./test_player rtxp_url rtp_type\r\n"
               << "例如:./test_player rtsp://admin:123456@127.0.0.1/live/0 0\r\n"
               << endl;
        return 0;
xzl committed
100

xiongziliang committed
101
    }
xzl committed
102

103 104 105 106 107 108 109 110
    MediaPlayer::Ptr player(new MediaPlayer());
    weak_ptr<MediaPlayer> weakPlayer = player;
    player->setOnPlayResult([weakPlayer](const SockException &ex) {
        InfoL << "OnPlayResult:" << ex.what();
        auto strongPlayer = weakPlayer.lock();
        if (ex || !strongPlayer) {
            return;
        }
xzl committed
111

112
        auto viedoTrack = strongPlayer->getTrack(TrackVideo, false);
xiongziliang committed
113 114
        if (!viedoTrack) {
            WarnL << "没有视频!";
115 116
            return;
        }
117 118

        AnyStorage::Ptr storage(new AnyStorage);
119 120
        viedoTrack->addDelegate(std::make_shared<FrameWriterInterfaceHelper>([storage](const Frame::Ptr &frame_in) {
            auto frame = Frame::getCacheAbleFrame(frame_in);
121 122 123
            SDLDisplayerHelper::Instance().doTask([frame,storage]() {
                auto &decoder = (*storage)["decoder"];
                auto &displayer = (*storage)["displayer"];
124
                auto &merger = (*storage)["merger"];
125
                if(!decoder){
xiongziliang committed
126
                    decoder.set<FFMpegDecoder>(frame->getCodecId());
127 128
                }
                if(!displayer){
xiongziliang committed
129
                    displayer.set<YuvDisplayer>(nullptr,url);
130
                }
131 132
                if(!merger){
                    merger.set<FrameMerger>();
xiongziliang committed
133
                }
134 135
                merger.get<FrameMerger>().inputFrame(frame,[&](uint32_t dts,uint32_t pts,const Buffer::Ptr &buffer){
                    AVFrame *pFrame = nullptr;
xiongziliang committed
136
                    bool flag = decoder.get<FFMpegDecoder>().inputVideo((unsigned char *) buffer->data(), buffer->size(), dts, &pFrame);
137 138 139 140
                    if (flag) {
                        displayer.get<YuvDisplayer>().displayYUV(pFrame);
                    }
                });
141 142 143
                return true;
            });
        }));
144
    });
145

xiongziliang committed
146

147 148 149
    player->setOnShutdown([](const SockException &ex) {
        ErrorL << "OnShutdown:" << ex.what();
    });
xiongziliang committed
150
    (*player)[kRtpType] = atoi(argv[2]);
151 152 153
    player->play(argv[1]);

    SDLDisplayerHelper::Instance().runLoop();
xiongziliang committed
154
    return 0;
xzl committed
155 156
}