zoukankan      html  css  js  c++  java
  • rtsp

    #include <SDKDDKVer.h> 
    #include <windows.h> 
    #include "main.h"
    #include "rtsp.h"  
    #include "lock.h"
    #include <sys/types.h>  
    #include <sys/stat.h>  
    extern "C"
    {
    #include <libavformat/avformat.h> 
    #include <libavdevice/avdevice.h>
    #include <libswscale/swscale.h> 
    #include <libavcodec/avcodec.h>
    }
    #ifdef __cplusplus  
    #define T LpRtsp_T
    #else 
    #define T Rtsp_T 
    #endif   
    
    typedef int(*tdf_framestream)(unsigned long fmid, unsigned char* frame[], unsigned char* info[], void*ctx);
    typedef int(*tdf_framefilter)(unsigned long fmid, unsigned char* frame[], unsigned char* info[], void*ctx);
    typedef int(*tdf_framereport)(unsigned long fmid, unsigned char* frame[], unsigned char* info[], void*ctx);
    
    struct Rtsp_T
    {
        AVFormatContext * format_context;
        AVInputFormat   * input_format;
        AVDictionary    * dictionary;
        AVCodecContext  * codec_context;
        AVCodec         * codec;
        AVPacket        * packet;
        SwsContext      * sws_context;
        AVFrame         * frame;
        AVFrame         * yuv;
        uint8_t         * buffer;
        HANDLE event; 
        HANDLE estop;
        int width;
        int height;
        int frame_size;
        int fps;
        int iindex;
        int isopen;
        const char* uri;
        const char* winname;
        const char* libname;
        void*ptr;
        void*ctx; 
        void(*print)(void*ctx, unsigned char* frame, int width, int height, int nbits);
        volatile long exit; 
        PTP_WORK pwk_stream;
        PTP_WORK pwk_filter;
        PTP_WORK pwk_report;
        tdf_framestream * pfstream;
        tdf_framefilter * pffilter;
        tdf_framereport * pfreport;
        LpLock_T * vlock;
        int numlock;
        long ref_signal;
        static long ref_count; 
    #ifdef _DEBUG
        long report_count;
        long filter_count; 
        long stream_count;
    #endif
    };
    long Rtsp_T::ref_count = 0;
    int Rtsp_isoff(T rt)
    {
        return rt->exit == 1;
    } 
    void Rtsp_close(T rt)
    { 
        if (!rt->isopen)
        {
            return;
        }
        if (rt->sws_context)
        {
            sws_freeContext(rt->sws_context);
            rt->sws_context = nullptr;
        }
        if (rt->frame)
        {
            av_free(rt->frame);
            rt->frame = nullptr;
        }
        if (rt->codec_context)
        {
            avcodec_close(rt->codec_context);
            rt->codec_context = nullptr;
        }
        if (rt->format_context)
        {
            avformat_close_input(&rt->format_context);
            rt->format_context = nullptr;
        } 
        rt->fps = -1;  
        rt->isopen = 0;
    }
    int Rtsp_open(T rt, const char* uri)
    {
        int ret = -1;
        if (rt->isopen)
        {
            return ret;
        }
        if (strcmp("file:///", uri) <= 0)
        {
    
        }
        else if (strcmp("rtsp://", uri) <= 0)
        {
            if (0 > (ret = av_dict_set(&rt->dictionary, "rtsp_transport", "tcp", 0)))
            {
                TRACE_LOG(" av_dict_set rtsp_transport failed");
                return ret;
            }
        }
        else
        {
            uri = nullptr;
            rt->input_format = av_find_input_format("vfwcap");
        }
        if (0 > (ret = av_dict_set(&rt->dictionary, "stimeout", "6000000", 0)))
        {
            TRACE_LOG("av_dict_set stimeout failed");
        }
        else if (0 > (ret = av_dict_set(&rt->dictionary, "list_devices", "true", 0)))
        {
            TRACE_LOG("av_dict_set list_devices failed");
        }
        else if (0 != (ret = avformat_open_input(&rt->format_context, uri, rt->input_format, &rt->dictionary)))
        {
            TRACE_LOG("avformat_open_input failed, ret = %d", ret);
        }
        else if (0 > (ret = avformat_find_stream_info(rt->format_context, nullptr)))
        {
            TRACE_LOG("avformat_find_stream_info failed, ret = %d", ret);
        }
        else
        {
            unsigned int i;
            for (i = 0; i < rt->format_context->nb_streams; ++i)
            {
                if (rt->format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
                {
                    break;
                }
            }
            if (rt->format_context->nb_streams == i)
            {
                TRACE_LOG("find video stream failed");
                ret = -1;
            }
            else
            {
                rt->iindex = i;
                rt->fps = rt->format_context->streams[i]->r_frame_rate.num
                    / rt->format_context->streams[i]->r_frame_rate.den;
                rt->codec_context = rt->format_context->streams[i]->codec;
                rt->codec = avcodec_find_decoder(rt->codec_context->codec_id);
                if (rt->codec == NULL)
                {
                    TRACE_LOG("find video stream failed");
                    ret = -1;
                }
                else if (0 > (ret = avcodec_open2(rt->codec_context, rt->codec, NULL)))
                {
                    TRACE_LOG("avcodec_open2 failed");
                    ret = -1;
                }
                else
                {
                    rt->width = rt->codec_context->width;
                    rt->height = rt->codec_context->height;
                    rt->frame_size = rt->width * rt->height;
                    rt->sws_context = sws_getContext(rt->width
                        , rt->height
                        , rt->codec_context->pix_fmt
                        , rt->width
                        , rt->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
                    rt->frame = av_frame_alloc();
                    ret = 0; 
                    rt->isopen = 1;
                }
            }
        }
        return ret;
    }
    int def_framestream(unsigned long fmid, unsigned char* frame[], unsigned char* info[], void*ctx)
    {
        T rt = (T)ctx;
        int retv = (-1); 
        if (!rt->exit)
        { 
            if (av_read_frame(rt->format_context, rt->packet) < 0)
            {
                TRACE_LOG("av_read_frame  failed");
            }
            else
            {
                if (nullptr == *frame)
                {
                    *frame = (unsigned char*)malloc(rt->frame_size);
                }
    #ifdef _DEBUG 
                long ref_count;
                if (0 == ( (ref_count = InterlockedIncrement(&rt->stream_count)) & REF_COUNT))
                    printf("stream frame..................................................%d 
    ", ref_count);
    #endif   
                retv = 0;
            }
        }
        return retv;
    }
    int def_framefilter(unsigned long fmid, unsigned char* frame[], unsigned char* info[], void*ctx)
    {
        T rt = (T)ctx;
        int gotptr ,retv = (-1);
        if (rt->packet->stream_index == rt->iindex)
        {
            if (avcodec_decode_video2(rt->codec_context, rt->frame, &gotptr, rt->packet) < 0)
            {
                TRACE_LOG(" avcodec_decode_video2 failed");
            }
            else if (gotptr)
            {  
                sws_scale
                (rt->sws_context
                    , rt->frame->data
                    , rt->frame->linesize
                    , 0
                    , rt->height
                    , rt->yuv->data
                    , rt->yuv->linesize);
                assert(frame); 
                memcpy_s(*frame, rt->frame_size, rt->yuv->data[0], rt->frame_size);
    #ifdef _DEBUG 
                long ref_count;
                if (0 == ((ref_count = InterlockedIncrement(&rt->filter_count)) & REF_COUNT))
                    printf("filter frame..................................................%d 
    ", ref_count);
    #endif  
                retv = 0;
            }
        } 
        return retv;
    }
    int def_framereport(unsigned long fmid, unsigned char** frame, unsigned char* info[], void*ctx)
    {
        T rt = (T)ctx;  
    #ifdef _DEBUG 
        long ref_count;
        if( 0 ==((ref_count = InterlockedIncrement(&rt->report_count)) & REF_COUNT))
            printf("report frame..................................................%d 
    ", ref_count);
    #endif 
        rt->print(rt->ctx, *frame, rt->width, rt->height, 8);
         *frame = nullptr;
        return 0;
    } 
    static VOID __stdcall __TrySubmitReportFrame(PTP_CALLBACK_INSTANCE instance, PVOID pv, PTP_WORK pwk)
    {
        T ap = (T)pv; 
        unsigned char*ptr = nullptr;
        int i, e = ap->numlock - 1;   
        while (0 == Lock_get(ap->vlock[e - 1], (void**)&ptr, 0))
        {/* 有数据就一直读 */ 
            for (i = 0; ap->pfreport[i]; ++i)
            {
                ap->pfreport[i](0, &ptr, nullptr, ap->ptr);
            }
            if (0 != Lock_put(ap->vlock[e], ptr, 0))
            {
                free(ptr);  
    #ifdef _DEBUG
                printf(" __TrySubmitReportFrame :Lock_put:timeout. 
     ");
    #endif
            }
            ptr = nullptr;
        }  
    }
    static VOID __stdcall __TrySubmitFilterFrame(PTP_CALLBACK_INSTANCE instance, PVOID pv, PTP_WORK pwk)
    {
        T ap = (T)pv; 
        unsigned char*ptr = nullptr;
        int i; 
        for (i = 0; ap->pffilter[i]; )
        {
            if (0 != Lock_get(ap->vlock[i], (void**)&ptr, 0))
            {
                ++i;
                continue; // 队列为空,暂时退出
            }
            if (0 !=ap->pffilter[i](0, &ptr, nullptr, ap->ptr) ||
                0 != Lock_put(ap->vlock[i + 1], ptr, 400))
            {
                free(ptr); 
    #ifdef _DEBUG
                printf(" __TrySubmitFilterFrame :Lock_put:timeout. 
     ");
    #endif
            }
            else if (nullptr == ap->pffilter[i + 1])
            { 
                SubmitThreadpoolWork(ap->pwk_report);
            }
            ptr = nullptr;
        } // for  
    }
    static VOID __stdcall __TrySubmitStreamFrame(PTP_CALLBACK_INSTANCE instance, PVOID pv, PTP_WORK pwk)
    {
        T ap = (T)pv; 
        unsigned char*ptr = nullptr;
        int e = ap->numlock - 1;
        int i; 
        for (i = 0; ap->pfstream[i]; ++i)
        {
            if (nullptr == ptr)
            {
                Lock_get(ap->vlock[e], (void**)&ptr, 0);
            }
            else
            {
    #ifdef _DEBUG
                printf(" __TrySubmitStreamFrame :Lock_put:timeout. 
     ");
    #endif
            }
            if (0 != ap->pfstream[i](0, &ptr, nullptr, ap->ptr))
            {
                if (InterlockedDecrementAcquire(&ap->ref_signal) <= 0)
                {
                    printf("__TrySubmitStreamFrame(ap) : SetEvent. 
    ");
                    SetEventWhenCallbackReturns(instance, ap->event);
                }
                break;
            }
            if (0 == Lock_put(ap->vlock[0], ptr, 700))
            { 
                SubmitThreadpoolWork(ap->pwk_filter);
                ptr = nullptr;
            }
            if (nullptr == ap->pfstream[i + 1])
            { 
                SubmitThreadpoolWork(pwk);
            } 
        } 
        if (nullptr != ptr)
        {
            free(ptr);
        }
    }
    static VOID __stdcall __TrySubmitApplyFrame(PTP_CALLBACK_INSTANCE instance, PVOID pv)
    { 
        T ap = (T)pv; 
        int i;   
        ap->packet = av_packet_alloc();
        ap->yuv = av_frame_alloc();
        ap->buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, ap->width, ap->height));
        avpicture_fill((AVPicture *)ap->yuv, ap->buffer, AV_PIX_FMT_YUV420P, ap->width, ap->height);
        ResetEvent(ap->estop);
    #ifdef _DEBUG
        ap->report_count = 0L;
        ap->filter_count = 0L;
        ap->stream_count = 0L;
    #endif
        for (i = 0; ap->pfstream[i]; ++i)
        { 
            SubmitThreadpoolWork(ap->pwk_stream);
        } 
    #ifdef _DEBUG
        printf("__TrySubmitApplyThread(ap) : Wait . 
    ");
    #endif
        CallbackMayRunLong(instance);
        WaitForSingleObject(ap->event, INFINITE);   
        {
            unsigned char *ptr = nullptr;  
            for (i = 0; i < ap->numlock;)
            {
                if (Lock_get(ap->vlock[i],(void**)&ptr, 700) == 0)
                    free(ptr); 
                else
                    ++i; 
            }
        }
    #ifdef _DEBUG
        printf("__TrySubmitApplyThread(ap)  : Free . 
    ");
    #endif
        av_frame_free(&ap->yuv);
        av_free(ap->buffer); 
        av_free_packet(ap->packet);
        free(ap->pfstream);
        free(ap->pffilter);
        free(ap->pfreport);  
        for (; ap->numlock-- > 0; )
        {
            Lock_free(&ap->vlock[ap->numlock]);
        }
        free(ap->vlock);  
        SetEvent(ap->estop);
    #ifdef _DEBUG
        printf("__TrySubmitApplyThread(ap)  : Exit . 
    ");
    #endif
    }
    static void Rtsp_apply(T ap, tdf_framestream stream[] = nullptr, tdf_framefilter filter[] = nullptr , tdf_framereport report[] = nullptr)
    {  
        int i, n = 0; 
        if (!stream || !stream[0])
        {
            i = 1;
            ap->pfstream = (tdf_framestream *)malloc((i + 1) * sizeof(*ap->pfstream));
            ap->pfstream[0] = def_framestream;
        }
        else
        {
            for (i = 0; stream[i]; ++i);
            ap->pfstream = (tdf_framestream *)malloc((i + 1) * sizeof(*ap->pfstream));
            for (i = 0; stream[i]; ++i)ap->pfstream[i] = stream[i];
        } 
        InterlockedExchangeAcquire(&ap->ref_signal,i);
        ap->pfstream[i] = nullptr;
        n += 1;
        //
        if (!filter || !filter[0])
        {
            i = 1;
            ap->pffilter = (tdf_framefilter*)malloc((i + 1) * sizeof(*ap->pffilter));
            ap->pffilter[0] = def_framefilter; 
        }
        else
        {
            for (i = 0; filter[i]; ++i);
            ap->pffilter = (tdf_framestream *)malloc((i + 1) * sizeof(*ap->pffilter));
            for (i = 0; filter[i]; ++i)ap->pffilter[i] = filter[i];
        }
        ap->pffilter[i] = nullptr;
        n += i;
        //
        if (!report || !report[0])
        {
            i = 1;
            ap->pfreport = (tdf_framefilter*)malloc((i + 1) * sizeof(*ap->pfreport));
            ap->pfreport[0] = def_framereport;
        }
        else
        {
            for (i = 0; report[i]; ++i);
            ap->pfreport = (tdf_framestream *)malloc((i + 1) * sizeof(*ap->pfreport));
            for (i = 0; report[i]; ++i)ap->pfreport[i] = report[i];
        }
        ap->pfreport[i] = nullptr;
        n += 1; 
        //
        ap->vlock = (LpLock_T *)malloc(n * sizeof *ap->vlock);
        for (ap->numlock = 0; ap->numlock < n; ++ap->numlock)
        {
            ap->vlock[ap->numlock] = Lock_new(3072);
        } 
        TrySubmitThreadpoolCallback(__TrySubmitApplyFrame, ap, NULL);
    }
    int Rtsp_stop(T rt)
    { 
        if (!rt->exit)
        {
            printf("Rtsp_stop. 
    ");
            InterlockedExchangeAcquire(&rt->exit, 1);
            WaitForSingleObject(rt->estop, INFINITE);
        }
        return 0;
    }
    int Rtsp_start(T rt, void*ctx, void(*print)(void*ctx, unsigned char* frame, int width, int height, int nbits))
    {  
        if (!print)
        {
            return (-1);
        }
        if (rt->exit)
        {
            rt->ctx = ctx;
            rt->ptr = rt;
            rt->print = print;
            printf("Rtsp_start. 
    ");
            InterlockedExchangeAcquire(&rt->exit, 0);
            Rtsp_apply(rt);
        }
        return 0;
    }
    T Rtsp_new()
    {
        LpRtsp_T rt = (LpRtsp_T)malloc(sizeof * rt);
        printf("Rtsp_new. 
    ");
        if (1 == InterlockedIncrementAcquire(&Rtsp_T::ref_count))
        {
            av_register_all();
            avdevice_register_all();
            avformat_network_init();
        }
        rt->format_context = avformat_alloc_context();
        rt->input_format = nullptr;
        rt->dictionary = nullptr;
        rt->codec_context = nullptr;
        rt->codec = nullptr;
        rt->packet = nullptr;
        rt->sws_context = nullptr;
        rt->frame = nullptr;
        rt->winname = nullptr;
        rt->uri = nullptr;
        rt->libname = nullptr;
        rt->ptr = nullptr;
        rt->exit = 1;
        rt->isopen = 0;
        rt->ctx = nullptr;
        rt->fps = -1;
        rt->event = CreateEvent(NULL, FALSE, FALSE, NULL); 
        rt->estop = CreateEvent(NULL, TRUE , FALSE, NULL);
        rt->pwk_stream = CreateThreadpoolWork(__TrySubmitStreamFrame, rt, NULL);
        rt->pwk_filter = CreateThreadpoolWork(__TrySubmitFilterFrame, rt, NULL);
        rt->pwk_report = CreateThreadpoolWork(__TrySubmitReportFrame, rt, NULL); 
        return rt;
    }
    void Rtsp_free(T * rt)
    {
        assert(rt&&&rt);
        printf("Rtsp_free. 
    ");
        avformat_close_input(&(*rt)->format_context);
        if (0 == InterlockedDecrementAcquire(&Rtsp_T::ref_count))
        {
            avformat_network_deinit();
        }
        CloseHandle((*rt)->event);
        CloseHandle((*rt)->estop);
        CloseThreadpoolWork((*rt)->pwk_stream);
        CloseThreadpoolWork((*rt)->pwk_filter);
        CloseThreadpoolWork((*rt)->pwk_report); 
        Rtsp_close(*rt);
        free(*rt);
        (*rt) = nullptr;
    }
  • 相关阅读:
    Codeforces Round #595 (Div. 3) A,B,C,D
    计算几何板子题【2019牛客国庆集训派对day7——三角形和矩形】【多边形相交的面积】
    [POJ]POJ1753(dfs)
    [POJ]POJ2965(dfs)
    洛谷 P1772 [ZJOI2006]物流运输 题解
    简单概率与期望
    洛谷 P3802 小魔女帕琪 题解
    用树状数组实现的平衡树
    【模板】扩展中国剩余定理(EXCRT)
    新博客开通通知
  • 原文地址:https://www.cnblogs.com/xuyouzhu/p/8989005.html
Copyright © 2011-2022 走看看