ChinaFFmpeg

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8116|回复: 0

[Android] 基于ffmpeg实现hls切片及dts monotonical increasing

[复制链接]
发表于 2015-6-24 09:34:33 | 显示全部楼层 |阅读模式
参考了论坛里面孙悟空的代码,基于ffmpeg的hls muxer实现了一个对ts的切片器,切片的动作是放在一个单独的线程里面实现的,第一次跑起来是没有问题,但是第二次跑起来就有问题了,如下:
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 7220696620 >= 7220505820
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 7220696620 >= 7220509420
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 7220696620 >= 7220513020
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 7220696620 >= 7220516620
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 7220696620 >= 7220520220
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 7220696620 >= 7220523820
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 1: 7220673201 >= 7220498241
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 1: 7220673201 >= 7220500401
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 1: 7220673201 >= 7220502561
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 1: 7220673201 >= 7220504721
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 1: 7220673201 >= 7220506881
Muxing Error, Discarding One Packet
[hls @ 0xb8774ec0] Application provided invalid, non monotonically increasing dts to muxer in stream 1: 7220673201 >= 7220509041


具体代码如下:

[C] 纯文本查看 复制代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <netinet/in.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <time.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#include <sys/time.h>

#include <pthread.h>
#include <api/libdvbrec/libprovider.h>
#include <api/libdvbrec/libhlssegmenter.h>

/*********************************************************************************************
*   Function Declaration(All Static)                                                                                                                                 *
*********************************************************************************************/

static int live_hls_segmenter_fill_iobuffer(void *opaque, uint8_t *buf, int buf_size);
static int record_hls_segmenter_fill_iobuffer(void *opaque, uint8_t *buf, int buf_size);


static int hls_segmenter_get_ip(char *ipaddr);
static int hls_segmenter_get_sys_time(char* localdate);
static int hls_segmenter_mkdir(const char* path);
static int hls_segmenter_set_url(char *pre_url);


static void* live_hls_segmenter_thread();
static void* record_hls_segmenter_thread();


static int live_hls_segmenter_start(struct dvbrec_stream_info* stream_info);
static int live_hls_segmenter_stop();


static int record_hls_segmenter_start(struct dvbrec_stream_info* stream_info);
static int record_hls_segmenter_stop();


static int record_set_index_name(char* index_filename);


static unsigned long int live_readdata_from_ring_buffer(unsigned char* buf, int size);
static unsigned long int record_readdata_from_ring_buffer(unsigned char* buf, int size);

/*********************************************************************************************
*   Function Definition                                                                                                                                 *
*********************************************************************************************/
static int hls_segmenter_set_url(char *pre_url)
{
    char* ip_addr[16] = {0};
    hls_segmenter_get_ip(ip_addr);
    memset(pre_url, 0x00, sizeof(pre_url));
    sprintf(pre_url, "http://");
    strcat(pre_url, ip_addr);
    strcat(pre_url, "/");    
    fprintf(stdout, "url = %s \n", pre_url);
    return 0;
}

static int hls_segmenter_mkdir(const char* path)
{
    DIR *dp;
    if ((dp = opendir(path)) == NULL)
    {
        //folder doesn't exist
        if(mkdir(path, S_IRWXU) == -1) {
            fprintf(stderr, "%s--%d--mkdir %s failure...\n",__FUNCTION__, __LINE__, path);
            return -1;
        }
        return 0;
    }
    if(dp)
        closedir(dp);
    return -1;
}

static int hls_segmenter_get_ip(char *ipaddr)
{
	int sock;
	struct sockaddr_in sin;
	struct ifreq ifr;
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock == -1) {
		perror("socket");
		return -1;	
	}
	strncpy(ifr.ifr_name, ETH_NAME, IFNAMSIZ);
	ifr.ifr_name[IFNAMSIZ - 1] = 0;
	if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) {
		perror("ioctl");
		return -1;
	}

	memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
	sprintf(ipaddr, "%s", inet_ntoa(sin.sin_addr));
	return 0;
}

static int hls_segmenter_get_sys_time(char* localdate)
{
       if(localdate == NULL) {
            fprintf(stderr, "%s--%d--localdate points to null...\n", __FUNCTION__, __LINE__);
            return -1;
       }
	time_t timep;
	struct tm* p;
	time(&timep);
	p = localtime(&timep);

	sprintf(localdate, "%d-%d-%d-%d-%d-%d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
       return 0;
}

static int record_set_index_name(char* index_filename)
{
    char* sys_time[20] = {0};
    hls_segmenter_get_sys_time(sys_time);
    strcat(index_filename, D_ROOT_DIR);
    strcat(index_filename, sys_time);
    strcat(index_filename, ".m3u8");
    fprintf(stdout, "index_filename = %s \n", index_filename);
    return 0;
}

static unsigned long int live_readdata_from_ring_buffer(unsigned char* buf, int size)
{
    struct timeval tv_begin, tv_end;
    unsigned long int actual_size =0;
    actual_size = media_provider_rpid_read(live_rb_id, buf, size);
    
    while(actual_size == 0) {
        usleep(30 * 1000);
        actual_size = media_provider_rpid_read(live_rb_id, buf, size);
    }
    
    HLS_SEG_PRINT(stdout, "%s()--%d--size = %d, actual_size = %d bytes--...\n",  __FUNCTION__, __LINE__, size, actual_size);
    return actual_size;
}

static unsigned long int record_readdata_from_ring_buffer(unsigned char* buf, int size)
{
    struct timeval tv_begin, tv_end;
    unsigned long int actual_size =0;
    actual_size = media_provider_rpid_read(record_rb_id, buf, size);
    
    while(actual_size == 0) {
        usleep(30 * 1000);
        actual_size = media_provider_rpid_read(record_rb_id, buf, size);
    }
    
    HLS_SEG_PRINT(stdout, "%s()--%d--size = %d, actual_size = %d bytes--...\n",  __FUNCTION__, __LINE__, size, actual_size);
    return actual_size;
}

static int live_hls_segmenter_fill_iobuffer(void *opaque, uint8_t *buf, int buf_size)
{
    return live_readdata_from_ring_buffer(buf, buf_size);
}

static int record_hls_segmenter_fill_iobuffer(void *opaque, uint8_t *buf, int buf_size)
{
    return record_readdata_from_ring_buffer(buf, buf_size);
}

static void* record_hls_segmenter_thread()
{ 
    record_terminate_seg = 0;

    int frame_index = 0;

    AVPacket pkt;
    AVFormatContext *input_fmtctx = NULL;
    AVFormatContext *output_fmtctx = NULL;
    
    unsigned char *aviobuffer = NULL;
    char *output_filename = "/data/hls_root/live.ts";
    char *index_filename[100] = {0};            //"/data/hls_root/2015-12-12-12-12-12.m3u8";
    char *sys_time[100] = {0};

    int ret = 0;
    int i = 0;
    int have_key = 0;
    static int first_pkt = 1;

    char* pre_url[100] = {0};

    hls_segmenter_mkdir(D_ROOT_DIR);

    record_set_index_name(index_filename);

    av_register_all();

    aviobuffer = (unsigned char *)av_mallocz(AVIOBUFFER_LENGTH);                         //need to be released after test
    if(aviobuffer == NULL) {
        fprintf(stderr, "av_malloc failure in segmenter...\n");
        return -1;
    }
//    memset(aviobuffer, 0x00, AVIOBUFFER_LENGTH);
    
    input_fmtctx = avformat_alloc_context();
    AVIOContext *avio = avio_alloc_context(aviobuffer, AVIOBUFFER_LENGTH, 0, NULL, record_hls_segmenter_fill_iobuffer, NULL, NULL);
    input_fmtctx->pb = avio;

    ret = avformat_open_input(&input_fmtctx, NULL, NULL, NULL);
    if (ret != 0) {
        fprintf(stderr, "Could not open input stream: %d\n", ret);
        exit(1);
    }
        
    if (avformat_find_stream_info(input_fmtctx, NULL) < 0) {
        fprintf(stderr, "Could not read stream information\n");
        exit(1);
    }
        
    av_dump_format(input_fmtctx, NULL, NULL, NULL);
 
    if (avformat_alloc_output_context2(&output_fmtctx, NULL, "hls", index_filename) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open the file %s\n", index_filename);
        return -ENOENT;
    }

    hls_segmenter_set_url(pre_url);
    av_opt_set(output_fmtctx->priv_data, "hls_time", "2", 0);
    av_opt_set(output_fmtctx->priv_data, "hls_base_url", "http://192.168.1.5/", 0);
 
    /* Process transcode parameters */
    for (i = 0; i < input_fmtctx->nb_streams; i++) {
        AVStream *out_stream = NULL;
        AVStream *in_stream = NULL;
        in_stream = input_fmtctx->streams[i];
        out_stream = avformat_new_stream(output_fmtctx, in_stream->codec->codec);
        if (out_stream < 0) {
            av_log(NULL, AV_LOG_ERROR, "Alloc new Stream error\n");
            return -EINVAL;
        }
        avcodec_copy_context(output_fmtctx->streams[i]->codec, input_fmtctx->streams[i]->codec);
        out_stream->codec->codec_tag = 0;
        if (output_fmtctx->oformat->flags & AVFMT_GLOBALHEADER) {
            out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
        }
    }
 
    av_dump_format(output_fmtctx, NULL, index_filename, 1);
 
 
    if (avio_open2(&output_fmtctx->pb, index_filename, AVIO_FLAG_WRITE, &output_fmtctx->interrupt_callback, NULL) < 0) {
        av_log(NULL, AV_LOG_ERROR, "cannot open the output file '%s'\n", index_filename);
        return -ENOENT;
    }
 
    if ((ret = avformat_write_header(output_fmtctx, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot write the header for the file '%s' ret = %d\n", index_filename, ret);
        return -ENOENT;
    }
 
 
    while (1) {
        AVStream *in_stream = NULL;
        AVStream *out_stream = NULL;
        
repeat:
        ret = av_read_frame(input_fmtctx, &pkt);
 
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Read Frame Error, Read Next Frame %d\n", ret);
            goto repeat;
        }
 
 
        if (pkt.pts == AV_NOPTS_VALUE && first_pkt) {
            pkt.pts = pkt.dts;
            first_pkt = 0;
        }
 
        in_stream = input_fmtctx->streams[pkt.stream_index];
        out_stream = output_fmtctx->streams[pkt.stream_index];
 
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;
        ret = av_write_frame(output_fmtctx, &pkt);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Muxing Error, Discarding One Packet\n");
            continue;
        }
        av_free_packet(&pkt);

        if(record_terminate_seg)
            break;
 
    }
 
    av_write_trailer(output_fmtctx);
    avformat_close_input(&input_fmtctx);
    avio_close(avio);
    avformat_free_context(output_fmtctx);
//    av_free(aviobuffer);

end:
    fprintf(stdout, "Record Segmenting Finish\n");
    return NULL;
}

static void* live_hls_segmenter_thread()
{ 
    live_terminate_seg = 0;

    int frame_index = 0;

    AVPacket pkt;
    AVFormatContext *input_fmtctx = NULL;
    AVFormatContext *output_fmtctx = NULL;
    
    unsigned char *aviobuffer = NULL;
    char *output_filename = "/data/hls_root/live.ts";
    char *index_filename = "/data/hls_root/live.m3u8";

    int ret = 0;
    int i = 0;
    int have_key = 0;
    static int first_pkt = 1;

    char* pre_url[25] = {0};

    hls_segmenter_mkdir(D_ROOT_DIR);

    av_register_all();

    aviobuffer = (unsigned char *)av_mallocz(AVIOBUFFER_LENGTH);                         //need to be released after test
    if(aviobuffer == NULL) {
        fprintf(stderr, "av_malloc failure in segmenter...\n");
        return -1;
    }
//    memset(aviobuffer, 0x00, AVIOBUFFER_LENGTH);
    
    input_fmtctx = avformat_alloc_context();
    AVIOContext *avio = avio_alloc_context(aviobuffer, AVIOBUFFER_LENGTH, 0, NULL, live_hls_segmenter_fill_iobuffer, NULL, NULL);
    input_fmtctx->pb = avio;

    ret = avformat_open_input(&input_fmtctx, NULL, NULL, NULL);
    if (ret != 0) {
        fprintf(stderr, "Could not open input stream: %d\n", ret);
        exit(1);
    }
        
    if (avformat_find_stream_info(input_fmtctx, NULL) < 0) {
        fprintf(stderr, "Could not read stream information\n");
        exit(1);
    }
        
    av_dump_format(input_fmtctx, NULL, NULL, NULL);
 
    if (avformat_alloc_output_context2(&output_fmtctx, NULL, "hls", index_filename) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot open the file %s\n", index_filename);
        return -ENOENT;
    }

    hls_segmenter_set_url(pre_url);
    av_opt_set(output_fmtctx->priv_data, "segment_time", D_DURATION, 0);
    av_opt_set(output_fmtctx->priv_data, "hls_base_url", pre_url, 0);
 
    for (i = 0; i < input_fmtctx->nb_streams; i++) {    // Process transcode parameters
        AVStream *out_stream = NULL;
        AVStream *in_stream = NULL;
        in_stream = input_fmtctx->streams[i];
        out_stream = avformat_new_stream(output_fmtctx, in_stream->codec->codec);
        if (out_stream < 0) {
            av_log(NULL, AV_LOG_ERROR, "Alloc new Stream error\n");
            return -EINVAL;
        }
        avcodec_copy_context(output_fmtctx->streams[i]->codec, input_fmtctx->streams[i]->codec);
        out_stream->codec->codec_tag = 0;
        if (output_fmtctx->oformat->flags & AVFMT_GLOBALHEADER) {
            out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
        }
    }
 
    av_dump_format(output_fmtctx, NULL, index_filename, 1);
 
    if (avio_open2(&output_fmtctx->pb, index_filename, AVIO_FLAG_WRITE, &output_fmtctx->interrupt_callback, NULL) < 0) {
        av_log(NULL, AV_LOG_ERROR, "cannot open the output file '%s'\n", index_filename);
        return -ENOENT;
    }
 
    if ((ret = avformat_write_header(output_fmtctx, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot write the header for the file '%s' ret = %d\n", index_filename, ret);
        return -ENOENT;
    }
 
    while (1) {
        AVStream *in_stream = NULL;
        AVStream *out_stream = NULL;
        
    repeat:
        ret = av_read_frame(input_fmtctx, &pkt);
 
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Read Frame Error, Read Next Frame %d\n", ret);
            goto repeat;
        }
 
        if (pkt.pts == AV_NOPTS_VALUE && first_pkt) {
            pkt.pts = pkt.dts;
            first_pkt = 0;
        }
 
        in_stream = input_fmtctx->streams[pkt.stream_index];
        out_stream = output_fmtctx->streams[pkt.stream_index];
 
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;
        ret = av_write_frame(output_fmtctx, &pkt);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Muxing Error, Discarding One Packet\n");
            continue;
        }
        av_free_packet(&pkt);

        if(live_terminate_seg)
            break;
    }
 
    av_write_trailer(output_fmtctx);
    avformat_close_input(&input_fmtctx);
    avio_close(avio);
    avformat_free_context(output_fmtctx);
//    av_free(aviobuffer);

    end:
    fprintf(stdout, "Live Segmenting Finish\n");
    return NULL;
}

static int live_hls_segmenter_start(struct dvbrec_stream_info* stream_info)
{
    live_seg_state = HSS_RUNNING;
    fprintf(stdout, "live_seg_state = HSS_RUNNING...\n");          

    media_provider_io_cmd(live_rb_id, REQUEST_STREAM_START, (UINT32)stream_info,  NULL);
    pthread_create(&live_hls_seg_thread_id, NULL, live_hls_segmenter_thread, NULL);

    return 0;
}

static int live_hls_segmenter_stop()
{
    live_terminate_seg = 1;
    
    pthread_join(live_hls_seg_thread_id, NULL);
    live_seg_state = HSS_IDLE;
    
    fprintf(stdout, "live_seg_state = HSS_IDLE...\n");
    
    return 0;
}

static int record_hls_segmenter_start(struct dvbrec_stream_info* stream_info)
{
    record_seg_state = HSS_RUNNING;
    fprintf(stdout, "record_seg_state = HSS_RUNNING...\n");          

    media_provider_io_cmd(record_rb_id, REQUEST_STREAM_START, (UINT32)stream_info,  NULL);
    pthread_create(&record_hls_seg_thread_id, NULL, record_hls_segmenter_thread, NULL);

    return 0;
}

static int record_hls_segmenter_stop()
{
    record_terminate_seg = 1;
    
    pthread_join(record_hls_seg_thread_id, NULL);
    record_seg_state = HSS_IDLE;
    
    fprintf(stdout, "record_seg_state = HSS_IDLE...\n");
    
    return 0;
}

HLS_RETURN_CODE hls_segmenter_cmd(HLS_SEG_CMD hls_seg_cmd, struct dvbrec_stream_info* stream_info)
{
    HLS_RETURN_CODE ret = HLS_CMD_EXEC_SUCCESS;

    if((CMD_START_LIVE == hls_seg_cmd || CMD_START_RECORD == hls_seg_cmd) && stream_info == NULL)
    {
        fprintf(stderr, "In file %s \n In function %s at L[%d]", __FILE__, __FUNCTION__, __LINE__);
        return HLS_CMD_EXEC_FAILURE;
    }
    
    if((live_seg_state == HSS_IDLE && record_seg_state == HSS_IDLE) || 
        CMD_START_LIVE == hls_seg_cmd || 
        CMD_START_RECORD == hls_seg_cmd)
    {
        fprintf(stdout, "Init Ring Buffer!\n");
        media_provider_init();                                    //initial mediaprovider        
    }

    fprintf(stdout, "pid[0] = %d\npid[1] = %d\npid[2] =  %d\npid[3] =  %d\npid[4] =  %d\n", 
        stream_info->pids[0], 
        stream_info->pids[1], 
        stream_info->pids[2], 
        stream_info->pids[3], 
        stream_info->pids[4]);
   
    switch(live_seg_state)
    {
        case HSS_IDLE:
            if(CMD_START_LIVE == hls_seg_cmd) {
                live_hls_segmenter_start(stream_info);
            }
            break;

        case HSS_RUNNING:
            if(CMD_STOP_LIVE == hls_seg_cmd) {
                live_hls_segmenter_stop();
            }
            break;
            
        default:
            break;
    }

    switch(record_seg_state)
    {
        case HSS_IDLE:
            if(CMD_START_RECORD == hls_seg_cmd) {
                record_hls_segmenter_start(stream_info);
            }
            break;

        case HSS_RUNNING:
            if(CMD_STOP_RECORD == hls_seg_cmd) {
                record_hls_segmenter_stop();
            }
            break;
            
        default:
            break;
    }

    if(live_seg_state == HSS_IDLE && record_seg_state == HSS_IDLE)
    {
        fprintf(stdout, "Destroy Ring Buffer!\n");
        media_provider_del();
    }

    return ret;
}


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|Archiver|ChinaFFmpeg

GMT+8, 2024-4-26 12:34 , Processed in 0.056254 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表