ts视频生成m3u8

#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

#define M3U8_TS_LEN 32

typedef struct {
    int fps;
    AVCodec *codec;
    AVFrame *frame;
    AVPacket *pkt;
    AVCodecContext *codec_ctx;
    //
    AVFormatContext *fmt_ctx;
} xvid_context;

typedef struct {
    char extm3u[M3U8_TS_LEN];                 // #EXTM3U
    char ext_x_version[M3U8_TS_LEN];          // #EXT-X-VERSION:3
    char ext_x_media_sequence[M3U8_TS_LEN];   // #EXT-X-MEDIA-SEQUENCE:0   播放对应的序列号
    char ext_x_allow_cache[M3U8_TS_LEN];      // #EXT-X-ALLOW-CACHE:YES
    char ext_x_targetduration[M3U8_TS_LEN];   // #EXT-X-TARGETDURATION:    指定媒体文件持续时间的最大值
    char ext_x_playlist_type[M3U8_TS_LEN];    // #EXT-X-PLAYLIST-TYPE
    char extinf[M3U8_TS_LEN];                 // #EXTINF:
    char ext_x_endlist[M3U8_TS_LEN];          // #EXT-X-ENDLIST
} m3u8_text;

static void xvid_encode_close(xvid_context *x);
static void xvid_format_close(AVFormatContext *fmt_ctx);


static void m3u8_init_data(m3u8_text *m3u8)
{
    memset(m3u8->extm3u, 0, M3U8_TS_LEN);
    memcpy(m3u8->extm3u, "#EXTM3U\n", strlen("#EXTM3U\n"));
    memset(m3u8->ext_x_version, 0, M3U8_TS_LEN);
    memcpy(m3u8->ext_x_version, "#EXT-X-VERSION:3\n", strlen("#EXT-X-VERSION:3\n"));
    memset(m3u8->ext_x_allow_cache, 0, M3U8_TS_LEN);
    memcpy(m3u8->ext_x_allow_cache, "#EXT-X-ALLOW-CACHE:YES\n", strlen("#EXT-X-ALLOW-CACHE:YES\n"));
    memset(m3u8->ext_x_targetduration, 0, M3U8_TS_LEN);
    memcpy(m3u8->ext_x_targetduration, "#EXT-X-TARGETDURATION:1800\n", strlen("#EXT-X-TARGETDURATION:1800\n"));
    memset(m3u8->ext_x_media_sequence, 0, M3U8_TS_LEN);
    memcpy(m3u8->ext_x_media_sequence, "#EXT-X-MEDIA-SEQUENCE:0\n", strlen("#EXT-X-MEDIA-SEQUENCE:0\n"));
    memset(m3u8->ext_x_playlist_type, 0, M3U8_TS_LEN);
    memcpy(m3u8->ext_x_playlist_type, "#EXT-X-PLAYLIST-TYPE:VOD\n", strlen("#EXT-X-PLAYLIST-TYPE:VOD\n"));    //点播
    memset(m3u8->extinf, 0, M3U8_TS_LEN);
    memcpy(m3u8->extinf, "#EXTINF:%f,\n", strlen("#EXTINF:%f,\n"));
    memset(m3u8->ext_x_endlist, 0, M3U8_TS_LEN);
    memcpy(m3u8->ext_x_endlist, "#EXT-X-ENDLIST\n", strlen("#EXT-X-ENDLIST\n"));
}

static void m3u8_write_header(m3u8_text *m3u8, FILE* m3u8_fp)
{
    fwrite((unsigned char*)m3u8->extm3u, 1, strlen(m3u8->extm3u), m3u8_fp);
    fwrite((unsigned char*)m3u8->ext_x_version, 1, strlen(m3u8->ext_x_version), m3u8_fp);
    fwrite((unsigned char*)m3u8->ext_x_media_sequence, 1, strlen(m3u8->ext_x_media_sequence), m3u8_fp);
    fwrite((unsigned char*)m3u8->ext_x_allow_cache, 1, strlen(m3u8->ext_x_allow_cache), m3u8_fp);
    fwrite((unsigned char*)m3u8->ext_x_targetduration, 1, strlen(m3u8->ext_x_targetduration), m3u8_fp);
    fwrite((unsigned char*)m3u8->ext_x_playlist_type, 1, strlen(m3u8->ext_x_playlist_type), m3u8_fp);
}

static int m3u8_write_trailer(m3u8_text *m3u8, FILE* m3u8_fp, const char *play_name)
{
    int ret;
    AVFormatContext *fmt_ctx = NULL;
    fmt_ctx = avformat_alloc_context();
    if ((ret = avformat_open_input(&fmt_ctx, play_name, NULL, NULL)) < 0 )
    {   
       fprintf(stderr,"-----avformat_open_input error: %s-----", play_name);
       return ret;
    } 
    if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0 )
    {   
       fprintf(stderr,"-----avformat_find_stream_info error: %s-----", play_name);
       return ret;
    } 

    char extinf[M3U8_TS_LEN] = { 0 };
    sprintf(extinf, m3u8->extinf, fmt_ctx->duration/1000000.0);
    fwrite((unsigned char*)extinf, 1, strlen(extinf), m3u8_fp);
    fwrite((unsigned char*)play_name, 1, strlen(play_name), m3u8_fp);
    fwrite((unsigned char*)"\n", 1, strlen("\n"), m3u8_fp);
    
    avformat_close_input(&fmt_ctx);
    avformat_free_context(fmt_ctx);
    return 0;
}

static int m3u8_write_endlist(m3u8_text *m3u8, FILE* m3u8_fp)
{
    fwrite((unsigned char*)m3u8->ext_x_endlist, 1, strlen(m3u8->ext_x_endlist), m3u8_fp);
}

static int xvid_encode_init(xvid_context *x)
{
    int ret;

    x->codec = avcodec_find_encoder_by_name("libxvid");
    if (!x->codec) {
        fprintf(stderr, "Codec not found\n");
        return -1;
    }

    x->codec_ctx = avcodec_alloc_context3(x->codec);
    if (!x->codec_ctx) {
        fprintf(stderr, "Could not allocate video codec context\n");
        return -1;
    }

    x->fps = 30;
    x->codec_ctx->bit_rate = 5000000;
    x->codec_ctx->width = 1280;
    x->codec_ctx->height = 720;
    x->codec_ctx->time_base = (AVRational){1, x->fps};
    x->codec_ctx->framerate = (AVRational){x->fps, 1};
    //codec_ctx->gop_size = 4;
    x->codec_ctx->max_b_frames = 2;
    x->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;

    ret = avcodec_open2(x->codec_ctx, x->codec, NULL);
    if (ret < 0) {
        fprintf(stderr,"Could not open codec: %s\n", av_err2str(ret));
        return -1;
    }

    x->frame = av_frame_alloc();
    if (!x->frame) {
        fprintf(stderr,"Could not allocate video frame\n");
        return -1;
    }
    x->frame->format = x->codec_ctx->pix_fmt;
    x->frame->width  = x->codec_ctx->width;
    x->frame->height = x->codec_ctx->height;
	
    ret = av_frame_get_buffer(x->frame, 32);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate the video frame data\n");
        return -1;
    }

    x->pkt = av_packet_alloc();
    if (!x->pkt) {
        return -1;
    }
}

static int xvid_format_init(xvid_context *x, const char *file_name)
{
    if (!x)
        return -1;

    int ret;
    // create out context
	avformat_alloc_output_context2(&x->fmt_ctx, 0, 0, file_name);
 
	// add video stream
    AVStream *st;
	st = avformat_new_stream(x->fmt_ctx, NULL);
	st->id = 0;
	st->codecpar->codec_tag = 0;
    avcodec_parameters_from_context(st->codecpar, x->codec_ctx);

    //av_dump_format(x->fmt_ctx, 0, file_name, 1);

    // write header
	ret = avio_open(&x->fmt_ctx->pb, file_name, AVIO_FLAG_WRITE);
	if (ret < 0)
	{
		fprintf(stderr," avio_open  failed! \n");
		return -1;
	}
	ret = avformat_write_header(x->fmt_ctx, NULL);
	if (ret < 0)
	{
		fprintf(stderr," avformat_write_header  failed! \n");
		return -1;
	}
}

static void xvid_encode_frame(xvid_context *x)
{
    int ret;
    ret = avcodec_send_frame(x->codec_ctx, x->frame);
    if (ret < 0) {
        fprintf(stderr, "Error sending a frame for encoding\n");
        exit(1);
    }
    while (ret >= 0) {
        ret = avcodec_receive_packet(x->codec_ctx, x->pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        else if (ret < 0) {
            fprintf(stderr, "Error during encoding\n");
            exit(1);
        }
        //printf("Write packet -- %3"PRId64" --(size=%5d)\n", x->pkt->pts, x->pkt->size);

        //将编码后的帧写入文件
		av_interleaved_write_frame(x->fmt_ctx, x->pkt);
        av_packet_unref(x->pkt);
    }
}

static void xvid_encode_close(xvid_context *x)
{
    //清理编码器上下文
    avcodec_free_context(&x->codec_ctx);
    av_frame_free(&x->frame);
    av_packet_free(&x->pkt);
}

static void xvid_format_close(AVFormatContext *fmt_ctx)
{
    //关闭视频输出IO
	avio_close(fmt_ctx->pb);
	//清理封装输出上下文
	avformat_free_context(fmt_ctx);
}

int main(int argc, char* argv[])
{
    int i, j, ret = -1;
    FILE *input_fp;
    FILE *m3u8_fp;
    unsigned int read_size;
    const char *ifile = "../test/clip.yuv";

    ///
    input_fp = fopen(ifile, "rb");
    if (input_fp == NULL)
    {
      fprintf(stderr, "Could not to open inputfile.\n");
      return -1;
    }

    m3u8_fp = fopen("ppppp.m3u8", "wb");
    if (m3u8_fp == NULL)
    {
      fprintf(stderr, "Could not to open m3u8_fp.\n");
      return -1;
    }

    xvid_context *x_ctx = (xvid_context *)malloc(sizeof(xvid_context));
    xvid_encode_init(x_ctx);
    xvid_format_init(x_ctx, "5555.ts");

    m3u8_text *m3u8 = (m3u8_text*)malloc(sizeof(m3u8_text));
    m3u8_init_data(m3u8);
    m3u8_write_header(m3u8, m3u8_fp);
    
    fseek(input_fp, 0, SEEK_END);
    unsigned int infile_size = ftell(input_fp);
    unsigned int frame_cnt = infile_size / (x_ctx->codec_ctx->width * x_ctx->codec_ctx->height*3/2);
    printf("frame_cnt frame_cnt %3d \n", frame_cnt);

    //av_opt_set(codec_ctx->priv_data, "preset", "slow", 0);
    /
    //av_dump_format(oc, 0, ofile, 1);
    
    fseek(input_fp, 0, SEEK_SET);
    // Loop over all frames in inputfile
    for (i = 0; i < frame_cnt; i++)
    {
        // Make sure the frame data is writable
        int rc = av_frame_make_writable(x_ctx->frame);
        if (rc < 0)
        {
          fprintf(stderr, "av_frame_make_writable error.\n");
          return -1;
        }

        // Read data for Y into frame buffer
        for (j = 0; j < x_ctx->codec_ctx->height; j++)
        {
          read_size = fread(&x_ctx->frame->data[0][0] + j * x_ctx->frame->linesize[0], x_ctx->codec_ctx->width, 1, input_fp);
          if (read_size != 1) {
            fprintf(stderr, "Failed to read Y. read_size=%u.\n", read_size);
            return -1;
          }
        }
        // Read data for U into frame buffer
        for (j = 0; j < x_ctx->codec_ctx->height / 2; j++)
        {
          read_size = fread(&x_ctx->frame->data[1][0] + j * x_ctx->frame->linesize[1], x_ctx->codec_ctx->width / 2, 1, input_fp);
          if (read_size != 1) {
            fprintf(stderr, "Failed to read U. read_size=%u.\n", read_size);
            return -1;
          }
        }
        // Read data for V into frame buffer
        for (j = 0; j < x_ctx->codec_ctx->height / 2; j++)
        {
          read_size = fread(&x_ctx->frame->data[2][0] + j * x_ctx->frame->linesize[2], x_ctx->codec_ctx->width / 2, 1, input_fp);
          if (read_size != 1)
          {
            fprintf(stderr, "Failed to read V. read_size=%u.\n", read_size);
            return -1;
          }
        }
        x_ctx->frame->pts = i * 90000 / x_ctx->fps;
    
        //
        if (i < 150)
        {
            xvid_encode_frame(x_ctx);
        }
        else {
            if (i == 150)
            {
                printf("150150105\n");
                av_write_trailer(x_ctx->fmt_ctx);
                xvid_format_close(x_ctx->fmt_ctx);
                xvid_format_init(x_ctx, "6666.ts");
            }
            
            xvid_encode_frame(x_ctx);
        }
    }
    /
    fclose(input_fp);
    //
	av_write_trailer(x_ctx->fmt_ctx);

    xvid_format_close(x_ctx->fmt_ctx);
    xvid_encode_close(x_ctx);
    //
    m3u8_write_trailer(m3u8, m3u8_fp, "5555.ts");
    m3u8_write_trailer(m3u8, m3u8_fp, "6666.ts");
    m3u8_write_endlist(m3u8, m3u8_fp);
    fclose(m3u8_fp);
    
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值