#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 \r\n", 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 \r\n", 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 \r\n", 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. \r\n ");
#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. \r\n ");
#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. \r\n ");
#endif
        }
        if (0 != ap->pfstream[i](0, &ptr, nullptr, ap->ptr))
        {
            if (InterlockedDecrementAcquire(&ap->ref_signal) <= 0)
            {
                printf("__TrySubmitStreamFrame(ap) : SetEvent. \r\n");
                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 . \r\n");
#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 . \r\n");
#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 . \r\n");
#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. \r\n");
        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. \r\n");
        InterlockedExchangeAcquire(&rt->exit, 0);
        Rtsp_apply(rt);
    }
    return 0;
}
T Rtsp_new()
{
    LpRtsp_T rt = (LpRtsp_T)malloc(sizeof * rt);
    printf("Rtsp_new. \r\n");
    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. \r\n");
    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;
}

 

posted on 2018-05-04 09:15  静观海月  阅读(334)  评论(0编辑  收藏  举报