142 lines
4.6 KiB
C++
142 lines
4.6 KiB
C++
#include "mov-reader.h"
|
|
#include "mov-format.h"
|
|
#include "mpeg4-avc.h"
|
|
#include "mpeg4-aac.h"
|
|
#include "flv-proto.h"
|
|
#include "flv-header.h"
|
|
#include "flv-writer.h"
|
|
#include "flv-muxer.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
extern "C" const struct mov_buffer_t* mov_file_buffer(void);
|
|
|
|
static uint8_t s_packet[2 * 1024 * 1024];
|
|
static uint8_t s_buffer[4 * 1024 * 1024];
|
|
static uint32_t s_aac_track;
|
|
static uint32_t s_avc_track;
|
|
static uint32_t s_txt_track;
|
|
static uint8_t s_video_type;
|
|
static struct flv_audio_tag_header_t s_audio_tag;
|
|
static struct flv_video_tag_header_t s_video_tag;
|
|
|
|
static int iskeyframe(const uint8_t* data, size_t bytes)
|
|
{
|
|
size_t nalu_length = 4;
|
|
uint32_t len;
|
|
|
|
while (bytes >= nalu_length + 1)
|
|
{
|
|
len = 0;
|
|
for (size_t i = 0; i < nalu_length; i++)
|
|
len = (len << 8) | data[i];
|
|
|
|
if (len + nalu_length > bytes)
|
|
return 0; // invalid
|
|
|
|
uint8_t nalu_type = (FLV_VIDEO_H264 == s_video_type) ? (data[nalu_length] & 0x1f) : ((data[nalu_length] >> 1) & 0x3f);
|
|
if ((FLV_VIDEO_H264 == s_video_type) ? (5 == nalu_type) : (16 <= nalu_type && nalu_type <= 23))
|
|
return 1;
|
|
|
|
bytes -= nalu_length + len;
|
|
data += nalu_length + len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void onread(void* flv, uint32_t track, const void* buffer, size_t bytes, int64_t pts, int64_t dts, int flags)
|
|
{
|
|
if (s_avc_track == track)
|
|
{
|
|
int keyframe = (FLV_VIDEO_H264 == s_video_type || FLV_VIDEO_H265 == s_video_type) ? iskeyframe((const uint8_t*)buffer, bytes) : flags;
|
|
printf("[V] pts: %08lld, dts: %08lld%s\n", pts, dts, keyframe ? " [I]" : "");
|
|
s_video_tag.keyframe = (keyframe ? 1 : 2);
|
|
s_video_tag.avpacket = FLV_AVPACKET;
|
|
s_video_tag.cts = (int32_t)(pts - dts);
|
|
flv_video_tag_header_write(&s_video_tag, s_packet, sizeof(s_packet));
|
|
memcpy(s_packet + 5, buffer, bytes);
|
|
flv_writer_input(flv, FLV_TYPE_VIDEO, s_packet, bytes + 5, (uint32_t)dts);
|
|
}
|
|
else if (s_aac_track == track)
|
|
{
|
|
printf("[A] pts: %08lld, dts: %08lld\n", pts, dts);
|
|
s_audio_tag.avpacket = FLV_AVPACKET;
|
|
int m = flv_audio_tag_header_write(&s_audio_tag, s_packet, sizeof(s_packet));
|
|
memcpy(s_packet + m, buffer, bytes); // AAC exclude ADTS
|
|
flv_writer_input(flv, FLV_TYPE_AUDIO, s_packet, bytes + m, (uint32_t)dts);
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
static void mov_video_info(void* flv, uint32_t track, uint8_t object, int /*width*/, int /*height*/, const void* extra, size_t bytes)
|
|
{
|
|
s_avc_track = track;
|
|
assert(MOV_OBJECT_H264 == object || MOV_OBJECT_HEVC == object || MOV_OBJECT_AV1 == object || MOV_OBJECT_VP9 == object);
|
|
s_video_type = MOV_OBJECT_H264 == object ? FLV_VIDEO_H264 : (MOV_OBJECT_HEVC == object ? FLV_VIDEO_H265 : FLV_VIDEO_AV1);
|
|
s_video_tag.codecid = s_video_type;
|
|
s_video_tag.keyframe = 1;
|
|
s_video_tag.avpacket = FLV_SEQUENCE_HEADER;
|
|
s_video_tag.cts = 0;
|
|
flv_video_tag_header_write(&s_video_tag, s_packet, sizeof(s_packet));
|
|
memcpy(s_packet + 5, extra, bytes);
|
|
flv_writer_input(flv, FLV_TYPE_VIDEO, s_packet, bytes + 5, 0);
|
|
}
|
|
|
|
static void mov_audio_info(void* flv, uint32_t track, uint8_t object, int channel_count, int /*bit_per_sample*/, int sample_rate, const void* extra, size_t bytes)
|
|
{
|
|
if (MOV_OBJECT_AAC == object || MOV_OBJECT_OPUS == object)
|
|
{
|
|
s_aac_track = track;
|
|
s_audio_tag.codecid = MOV_OBJECT_AAC == object ? FLV_AUDIO_AAC : FLV_AUDIO_OPUS;
|
|
s_audio_tag.rate = 3; // 44k-SoundRate
|
|
s_audio_tag.bits = 1; // 16-bit samples
|
|
s_audio_tag.channels = 1; // Stereo sound
|
|
s_audio_tag.avpacket = FLV_SEQUENCE_HEADER;
|
|
int m = flv_audio_tag_header_write(&s_audio_tag, s_packet, sizeof(s_packet));
|
|
|
|
memcpy(s_packet + m, extra, bytes);
|
|
flv_writer_input(flv, FLV_TYPE_AUDIO, s_packet, bytes + m, 0);
|
|
}
|
|
}
|
|
|
|
static int mov_meta_info(void* flv, int type, const void* data, size_t bytes, uint32_t timestamp)
|
|
{
|
|
return flv_writer_input(flv, FLV_TYPE_SCRIPT, data, bytes, 0);
|
|
}
|
|
|
|
void mov_2_flv_test(const char* mp4)
|
|
{
|
|
snprintf((char*)s_packet, sizeof(s_packet), "%s.flv", mp4);
|
|
|
|
FILE* fp = fopen(mp4, "rb");
|
|
mov_reader_t* mov = mov_reader_create(mov_file_buffer(), fp);
|
|
void* flv = flv_writer_create((char*)s_packet);
|
|
|
|
//flv_muxer_t* muxer = flv_muxer_create(mov_meta_info, flv);
|
|
//memset(&metadata, 0, sizeof(metadata));
|
|
//metadata.videocodecid = FLV_VIDEO_H264;
|
|
//metadata.videodatarate = 2000;
|
|
//metadata.framerate = 25.0;
|
|
//metadata.width = 1280;
|
|
//metadata.height = 720;
|
|
//flv_muxer_metadata(muxer, &metadata);
|
|
//flv_muxer_destroy(muxer);
|
|
|
|
struct mov_reader_trackinfo_t info = { mov_video_info, mov_audio_info };
|
|
mov_reader_getinfo(mov, &info, flv);
|
|
|
|
while (mov_reader_read(mov, s_buffer, sizeof(s_buffer), onread, flv) > 0)
|
|
{
|
|
}
|
|
|
|
mov_reader_destroy(mov);
|
|
flv_writer_destroy(flv);
|
|
fclose(fp);
|
|
}
|