libdvbpsi 소스 코드 분석 (2) main 함수

13392 단어 mainlibdvbpsi
demon dvbinfo. c 의 main 함수 입구 분석:
        분석 편 의 를 위해 매크로 HAVESYS_SOCKET_H 격 리 된 socket 코드 를 제거 하고 libdvbpsi 자체 의 실현 에 만 관심 을 가 집 니 다.
    1. 데이터 구조의 디자인:
1.1 포획 기 capture 의 데이터 구 조 는 다음 과 같다.
typedef struct dvbinfo_capture_s
{
    fifo_t  *fifo;
    fifo_t  *empty;

    pthread_mutex_t lock;
    pthread_cond_t  fifo_full;
    bool     b_fifo_full;

    size_t   size;  /* prefered capture size */

    params_t *params;
    bool      b_alive;
} dvbinfo_capture_t;
데이터 구조 에서 알 수 있 듯 이 demo 는 현지의 autotest 이기 때문에 유명한 파이프 fifo 로 테스트 한다.명령 행 터미널 에서 ts 스 트림 파일 을 읽 고 한 스 레 드 는 buffer 의 데이터 push 를 fifo 에 계속 들 어 갑 니 다. 또한 메 인 스 레 드 는 fifo pop 에서 데 이 터 를 계속 내 보 내 고 해석 합 니 다. fifo 에서 읽 은 데 이 터 는 0 1.2, dvbinfo 입 니 다.capture_t 중의 paramst 구조 체
typedef struct params_s
{
    /* parameters */
    char *output;
    char *input;

    int  port;
    char *mcast_interface;

    bool b_udp;
    bool b_tcp;
    bool b_file;

    /* */
    int  fd_in;
    int  fd_out;

    int  debug;
    bool b_verbose;
    bool b_monitor; /* run in daemon mode */

    /* statistics */
    bool b_summary; /* write summary */
    struct summary_s {
        int mode;       /* one of: i_summary_mode */
        int64_t period; /* summary period in ms */
        char *file;     /* summary file name    */
        FILE *fd;       /* summary file descriptor */
    } summary;

    /* read data from file of socket */
    ssize_t (*pf_read)(int fd, void *buf, size_t count);
    ssize_t (*pf_write)(int fd, const void *buf, size_t count);
} params_t;
2. main 함수 입구
int main(int argc, char **pp_argv)
{
    dvbinfo_capture_t capture;
    params_t *param = NULL;
    char c;
   
    if (argc == 1)
        usage();

    param = params_init();
    capture.params = param;
    capture.fifo = fifo_new();
    capture.empty = fifo_new();
    capture.b_fifo_full = false;
    pthread_mutex_init(&capture.lock, NULL);		//     
    pthread_cond_init(&capture.fifo_full, NULL);	//       

    static const struct option long_options[] =
    {
        { "debug",     required_argument, NULL, 'd' },
        { "help",      no_argument,       NULL, 'h' },
        /* - inputs - */
        { "file",      required_argument, NULL, 'f' },
        { NULL, 0, NULL, 0 }
    };
	/*
	       
	*/
    while ((c = getopt_long(argc, pp_argv, "d:f:h", long_options, NULL)) != -1)
    {
        switch(c)
        {
            case 'd':
                if (optarg)
                {
                    param->debug = 0;
                    if (strncmp(optarg, "error", 5) == 0)
                        param->debug = 1;
                    else if (strncmp(optarg, "warn", 4) == 0)
                        param->debug = 2;
                    else if (strncmp(optarg, "debug", 5) == 0)
                        param->debug = 3;
                }
                break;

            case 'f':
                if (optarg)
                {
					/*  ts   ,  asprintf   */
                    if (asprintf(&param->input, "%s", optarg) < 0)
                    {
                        fprintf(stderr, "error: out of memory
"); params_free(param); usage(); } /* */ param->pf_read = read; param->b_file = true; } break; case ':': fprintf(stderr, "Option %c is missing arguments
", c); params_free(param); exit(EXIT_FAILURE); break; case '?': fprintf(stderr, "Unknown option %c found
", c); params_free(param); exit(EXIT_FAILURE); break; case 'h': default: params_free(param); usage(); break; } }; if (param->input == NULL) { libdvbpsi_log(param, DVBINFO_LOG_ERROR, "No source given
"); params_free(param); usage(); /* exits application */ } { capture.size = 188; //ts packet 188 libdvbpsi_log(param, DVBINFO_LOG_INFO, "Examining: %s
", param->input); } /* Capture thread */ dvbinfo_open(param); // ts , pthread_t handle; // pid capture.b_alive = true; /* capture */ if (pthread_create(&handle, NULL, dvbinfo_capture, (void *)&capture) < 0) { libdvbpsi_log(param, DVBINFO_LOG_ERROR, "failed creating thread
"); dvbinfo_close(param); params_free(param); exit(EXIT_FAILURE); } /* fifo , PSI */ int err = dvbinfo_process(&capture); /* fifo 0, ts 。 cpature alive false, */ capture.b_alive = false; /* stop thread */ if (pthread_join(handle, NULL) < 0) libdvbpsi_log(param, DVBINFO_LOG_ERROR, "error joining capture thread
"); dvbinfo_close(param); /* cleanup */ fifo_wake((&capture)->fifo); fifo_wake((&capture)->empty); fifo_free((&capture)->fifo); fifo_free((&capture)->empty); pthread_mutex_destroy(&capture.lock); pthread_cond_destroy(&capture.fifo_full); params_free(param); if (err < 0) exit(EXIT_FAILURE); else exit(EXIT_SUCCESS); }
3. 스 레 드 인 스 턴 스 (루틴) dvbinfocapture 의 분석 [주해] 스 레 드 dvbinfocapture 는 ts 스 트림 파일 push 를 fifo 에 계속 넣 는 동시에 dvbinfoprocess 는 fifo 에서 데 이 터 를 계속 꺼 내 고 모든 specific decoder 에 section 분석 을 제공 하여 table 표 의 재 구축 을 완성 합 니 다.스 레 드 dvbinfo 까지capture 는 ts 스 트림 파일 을 읽 었 고 dvbinfoprocess 처리 가 완료 되 어야 capture 의 활동 표지 위 capture. balive 는 false 로 설정 하고 마지막 으로 스 레 드 를 종료 하 며 스 레 드 자원 을 방출 합 니 다.전형 적 인 '생산자 - 소비자' 모델.
static void *dvbinfo_capture(void *data)
{
    dvbinfo_capture_t *capture = (dvbinfo_capture_t *)data;
    const params_t *param = capture->params;
    bool b_eof = false;

    while (capture->b_alive && !b_eof)
    {
        buffer_t *buffer;

        if (fifo_count(capture->empty) == 0)
            buffer = buffer_new(capture->size);
        else
            buffer = fifo_pop(capture->empty);

        if (buffer == NULL) /* out of memory */
            break;

        ssize_t size = param->pf_read(param->fd_in, buffer->p_data, buffer->i_size);
        if (size < 0) /* short read ? */
        {
            fifo_push(capture->empty, buffer);
            continue;
        }
        else if (size == 0)
        {
            fifo_push(capture->empty, buffer);
            b_eof = true;
            continue;
        }

        buffer->i_date = mdate();

        /* check fifo size */
        if (fifo_size(capture->fifo) >= FIFO_THRESHOLD_SIZE)
        {
            pthread_mutex_lock(&capture->lock);
            capture->b_fifo_full = true;
            pthread_mutex_unlock(&capture->lock);

            if (param->b_file)
            {
                /* wait till buffer becomes smaller again */
                pthread_mutex_lock(&capture->lock);
                while(capture->b_fifo_full)
                    pthread_cond_wait(&capture->fifo_full, &capture->lock);
                pthread_mutex_unlock(&capture->lock);
            }
            else
            {
                libdvbpsi_log(capture->params, DVBINFO_LOG_ERROR,
                          "error fifo full discarding buffer");
                fifo_push(capture->empty, buffer);
                continue;
            }
        }

        /* store buffer */
        fifo_push(capture->fifo, buffer);
        buffer = NULL;
    }

    capture->b_alive = false;
    fifo_wake(capture->fifo);
    return NULL;
}
4、dvbinfo_process 는 ts 흐름 에서 각종 table 의 해석 을 책임 집 니 다
static int dvbinfo_process(dvbinfo_capture_t *capture)
{
    int err = -1;
    bool b_error = false;
    params_t *param = capture->params;
    buffer_t *buffer = NULL;

    char *psz_temp = NULL;
    mtime_t deadline = 0;
    if (param->b_summary)
    {
        if (asprintf(&psz_temp, "%s.part", param->summary.file) < 0)
        {
            libdvbpsi_log(param, DVBINFO_LOG_ERROR, "Could not create temporary summary file %s
", param->summary.file); return err; } deadline = mdate() + param->summary.period; } /*MPEG-TS PSI decoders create*/ ts_stream_t *stream = libdvbpsi_init(param->debug, &libdvbpsi_log, (void *)param); if (!stream) goto out; while (!b_error) { /* Wait till fifo has emptied */ if (!capture->b_alive && (fifo_count(capture->fifo) == 0)) break; /* Wait for data to arrive */ buffer = fifo_pop(capture->fifo); if (buffer == NULL) continue; if (param->output) { size_t size = param->pf_write(param->fd_out, buffer->p_data, buffer->i_size); if (size < 0) /* error writing */ { libdvbpsi_log(param, DVBINFO_LOG_ERROR, "error (%d) writting to %s", errno, param->output); break; } else if (size < buffer->i_size) /* short writting disk full? */ { libdvbpsi_log(param, DVBINFO_LOG_ERROR, "error writting to %s (disk full?)", param->output); break; } } if (!libdvbpsi_process(stream, buffer->p_data, buffer->i_size, buffer->i_date)) b_error = true; /* summary statistics */ if (param->b_summary) { if (mdate() >= deadline) { FILE *fd = fopen(psz_temp, "w+"); if (fd) { libdvbpsi_summary(fd, stream, param->summary.mode); fflush(fd); fclose(fd); unlink(param->summary.file); rename(psz_temp, param->summary.file); } else { libdvbpsi_log(param, DVBINFO_LOG_ERROR, "failed opening summary file (disabling summary logging)
"); param->b_summary = false; } deadline = mdate() + param->summary.period; } } /* reuse buffer */ fifo_push(capture->empty, buffer); buffer = NULL; /* check fifo size */ if (fifo_size(capture->fifo) < FIFO_THRESHOLD_SIZE) { pthread_mutex_lock(&capture->lock); capture->b_fifo_full = false; pthread_cond_signal(&capture->fifo_full); pthread_mutex_unlock(&capture->lock); } } assert(fifo_count(capture->fifo) == 0); libdvbpsi_exit(stream); err = 0; out: if (b_error) libdvbpsi_log(param, DVBINFO_LOG_ERROR, "error while processing
" ); if (buffer) buffer_free(buffer); free(psz_temp); return err; }

좋은 웹페이지 즐겨찾기