#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;
}
ts视频生成m3u8
最新推荐文章于 2023-04-12 13:06:12 发布