|
参考了论坛里面孙悟空的代码,基于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;
}
|
|