?? quicktime.c
字號:
#include "quicktime.h"
int quicktime_make_streamable(char *in_path, char *out_path)
{
quicktime_t file, *old_file, new_file;
int moov_exists = 0, mdat_exists = 0, result, atoms = 1;
long mdat_start, mdat_size;
quicktime_atom_t leaf_atom;
long moov_length;
quicktime_init(&file);
/* find the moov atom in the old file */
if(!(file.stream = fopen(in_path, "rb")))
{
perror("quicktime_make_streamable");
return 1;
}
fseek(file.stream, 0, SEEK_END);
file.total_length = ftell(file.stream);
fseek(file.stream, 0, SEEK_SET);
/* get the locations of moov and mdat atoms */
do
{
/*printf("%x\n", quicktime_position(&file)); */
result = quicktime_atom_read_header(&file, &leaf_atom);
if(!result)
{
if(quicktime_atom_is(&leaf_atom, "moov"))
{
moov_exists = atoms;
moov_length = leaf_atom.size;
}
else
if(quicktime_atom_is(&leaf_atom, "mdat"))
{
mdat_start = quicktime_position(&file) - HEADER_LENGTH;
mdat_size = leaf_atom.size;
mdat_exists = atoms;
}
quicktime_atom_skip(&file, &leaf_atom);
atoms++;
}
}while(!result && quicktime_position(&file) < file.total_length);
fclose(file.stream);
if(!moov_exists)
{
printf("quicktime_make_streamable: no moov atom\n");
return 1;
}
if(!mdat_exists)
{
printf("quicktime_make_streamable: no mdat atom\n");
return 1;
}
/* copy the old file to the new file */
if(moov_exists && mdat_exists)
{
/* moov wasn't the first atom */
if(moov_exists > 1)
{
char *buffer;
long buf_size = 1000000;
result = 0;
/* read the header proper */
if(!(old_file = quicktime_open(in_path, 1, 0, 0)))
{
return 1;
}
quicktime_shift_offsets(&(old_file->moov), moov_length);
/* open the output file */
if(!(new_file.stream = fopen(out_path, "wb")))
{
perror("quicktime_make_streamable");
result = 1;
}
else
{
/* set up some flags */
new_file.wr = 1;
new_file.rd = 0;
quicktime_write_moov(&new_file, &(old_file->moov));
quicktime_set_position(old_file, mdat_start);
if(!(buffer = calloc(1, buf_size)))
{
result = 1;
printf("quicktime_make_streamable: out of memory\n");
}
else
{
while(quicktime_position(old_file) < mdat_start + mdat_size && !result)
{
if(quicktime_position(old_file) + buf_size > mdat_start + mdat_size)
buf_size = mdat_start + mdat_size - quicktime_position(old_file);
if(!quicktime_read_data(old_file, buffer, buf_size)) result = 1;
if(!result)
{
if(!quicktime_write_data(&new_file, buffer, buf_size)) result = 1;
}
}
free(buffer);
}
fclose(new_file.stream);
}
quicktime_close(old_file);
}
else
{
printf("quicktime_make_streamable: header already at 0 offset\n");
return 0;
}
}
return 0;
}
int quicktime_set_time_scale(quicktime_t *file, int time_scale)
{
file->moov.mvhd.time_scale = time_scale;
}
int quicktime_set_copyright(quicktime_t *file, char *string)
{
quicktime_set_udta_string(&(file->moov.udta.copyright), &(file->moov.udta.copyright_len), string);
}
int quicktime_set_name(quicktime_t *file, char *string)
{
quicktime_set_udta_string(&(file->moov.udta.name), &(file->moov.udta.name_len), string);
}
int quicktime_set_info(quicktime_t *file, char *string)
{
quicktime_set_udta_string(&(file->moov.udta.info), &(file->moov.udta.info_len), string);
}
int quicktime_get_time_scale(quicktime_t *file)
{
return file->moov.mvhd.time_scale;
}
char* quicktime_get_copyright(quicktime_t *file)
{
return file->moov.udta.copyright;
}
char* quicktime_get_name(quicktime_t *file)
{
return file->moov.udta.name;
}
char* quicktime_get_info(quicktime_t *file)
{
return file->moov.udta.info;
}
int quicktime_get_iod_audio_profile_level(quicktime_t *file)
{
return file->moov.iods.audioProfileId;
}
int quicktime_set_iod_audio_profile_level(quicktime_t *file, int id)
{
quicktime_iods_set_audio_profile(&file->moov.iods, id);
}
int quicktime_get_iod_video_profile_level(quicktime_t *file)
{
return file->moov.iods.videoProfileId;
}
int quicktime_set_iod_video_profile_level(quicktime_t *file, int id)
{
quicktime_iods_set_video_profile(&file->moov.iods, id);
}
int quicktime_video_tracks(quicktime_t *file)
{
int i, result = 0;
for(i = 0; i < file->moov.total_tracks; i++)
{
if(file->moov.trak[i]->mdia.minf.is_video) result++;
}
return result;
}
int quicktime_audio_tracks(quicktime_t *file)
{
int i, result = 0;
quicktime_minf_t *minf;
for(i = 0; i < file->moov.total_tracks; i++)
{
minf = &(file->moov.trak[i]->mdia.minf);
if(minf->is_audio)
result++;
}
return result;
}
int quicktime_set_audio(quicktime_t *file,
int channels,
long sample_rate,
int bits,
int sample_size,
int time_scale,
int sample_duration,
char *compressor)
{
int i, j;
quicktime_trak_t *trak;
/* delete any existing tracks */
for(i = 0; i < file->total_atracks; i++) {
for (j = 0; j < file->atracks[i].totalHintTracks; j++) {
quicktime_delete_trak(&(file->moov),
file->atracks[i].hintTracks[j]);
free(file->atracks[i].hintTracks[j]);
file->atracks[i].hintTracks[j] = NULL;
file->total_hint_tracks--;
}
quicktime_delete_audio_map(&(file->atracks[i]));
quicktime_delete_trak(&(file->moov), file->atracks[i].track);
}
free(file->atracks);
file->atracks = NULL;
file->total_atracks = 0;
if(channels) {
/* Fake the bits parameter for some formats. */
if(quicktime_match_32(compressor, QUICKTIME_ULAW) ||
quicktime_match_32(compressor, QUICKTIME_IMA4)) bits = 16;
file->atracks = (quicktime_audio_map_t*)
calloc(1, sizeof(quicktime_audio_map_t));
trak = quicktime_add_track(&(file->moov));
quicktime_trak_init_audio(file, trak, channels, sample_rate, bits,
sample_size, time_scale, sample_duration, compressor);
quicktime_init_audio_map(&(file->atracks[0]), trak);
file->atracks[file->total_atracks].track = trak;
file->atracks[file->total_atracks].channels = channels;
file->atracks[file->total_atracks].current_position = 0;
file->atracks[file->total_atracks].current_chunk = 1;
file->total_atracks++;
}
return 1; /* Return the number of tracks created */
}
int quicktime_set_video(quicktime_t *file,
int tracks,
int frame_w,
int frame_h,
float frame_rate,
int time_scale,
char *compressor)
{
int i, j;
quicktime_trak_t *trak;
/* delete any existing tracks */
for(i = 0; i < file->total_vtracks; i++) {
for (j = 0; j < file->vtracks[i].totalHintTracks; j++) {
quicktime_delete_trak(&(file->moov),
file->vtracks[i].hintTracks[j]);
file->vtracks[i].hintTracks[j] = NULL;
file->total_hint_tracks--;
}
quicktime_delete_video_map(&(file->vtracks[i]));
quicktime_delete_trak(&(file->moov), file->vtracks[i].track);
}
free(file->vtracks);
file->vtracks = NULL;
file->total_vtracks = 0;
if (tracks > 0) {
file->total_vtracks = tracks;
file->vtracks = (quicktime_video_map_t*)calloc(1, sizeof(quicktime_video_map_t) * file->total_vtracks);
for(i = 0; i < tracks; i++)
{
trak = quicktime_add_track(&(file->moov));
quicktime_trak_init_video(file, trak, frame_w, frame_h, frame_rate,
time_scale, compressor);
quicktime_init_video_map(&(file->vtracks[i]), trak);
}
}
return 0;
}
int quicktime_set_audio_hint(quicktime_t *file, int audioTrack,
char *payloadName, u_int* pPayloadNumber,
int maxPktSize)
{
quicktime_audio_map_t* pMap = NULL;
quicktime_trak_t* hintTrak = NULL;
int timeScale;
float frameRate;
int sampleDuration;
char rtpMapBuf[128];
char sdpBuf[256];
/* check our arguments */
if (file == NULL) {
return -1;
}
if (audioTrack < 0 || audioTrack > file->total_atracks) {
return -1;
}
if (payloadName == NULL) {
return -1;
}
pMap = &file->atracks[audioTrack];
timeScale = quicktime_audio_time_scale(file, audioTrack);
if (timeScale == 0) {
return -1;
}
sampleDuration = file->atracks[audioTrack].track->mdia.minf.stbl.stts.table[0].sample_duration;
/* add the hint track */
hintTrak = quicktime_add_track(&(file->moov));
if (*pPayloadNumber == 0) {
(*pPayloadNumber) = 96 + file->total_hint_tracks++;
}
/* initialize it to reference the audio track */
quicktime_trak_init_hint(file, hintTrak, pMap->track,
maxPktSize, timeScale, sampleDuration);
/* set the payload info */
hintTrak->hint_udta.hinf.payt.payloadNumber = *pPayloadNumber;
sprintf(rtpMapBuf, "%s/%u", payloadName, timeScale);
strcpy(hintTrak->hint_udta.hinf.payt.rtpMapString, rtpMapBuf);
/* set the SDP media section */
sprintf(sdpBuf,
"m=audio 0 RTP/AVP %u\015\012a=rtpmap:%u %s\015\012a=control:trackID=%u\015\012",
*pPayloadNumber, *pPayloadNumber, rtpMapBuf, hintTrak->tkhd.track_id);
quicktime_sdp_set(&(hintTrak->hint_udta.hnti.sdp), sdpBuf);
pMap->hintTracks[pMap->totalHintTracks] = hintTrak;
pMap->hintPositions[pMap->totalHintTracks] = 0;
pMap->totalHintTracks++;
return (pMap->totalHintTracks - 1);
}
int quicktime_set_video_hint(quicktime_t *file, int videoTrack,
char *payloadName, u_int* pPayloadNumber,
int maxPktSize)
{
quicktime_video_map_t* pMap = NULL;
quicktime_trak_t* hintTrak = NULL;
float frameRate;
int timeScale;
int sampleDuration;
char rtpMapBuf[128];
char sdpBuf[1024];
/* check our arguments */
if (file == NULL) {
return -1;
}
if (videoTrack < 0 || videoTrack > file->total_vtracks) {
return -1;
}
if (payloadName == NULL) {
return -1;
}
frameRate = quicktime_video_frame_rate(file, videoTrack);
if (frameRate == 0.0) {
return -1;
}
timeScale = quicktime_video_time_scale(file, videoTrack);
if (timeScale == 0) {
return -1;
}
sampleDuration = timeScale / frameRate;
if (sampleDuration == 0) {
return -1;
}
/* add the hint track */
hintTrak = quicktime_add_track(&(file->moov));
if (*pPayloadNumber == 0) {
(*pPayloadNumber) = 96 + file->total_hint_tracks++;
}
pMap = &file->vtracks[videoTrack];
/* initialize it to reference the video track */
quicktime_trak_init_hint(file, hintTrak, pMap->track,
maxPktSize, timeScale, sampleDuration);
/* set the payload info */
hintTrak->hint_udta.hinf.payt.payloadNumber = *pPayloadNumber;
sprintf(rtpMapBuf, "%s/90000", payloadName);
strcpy(hintTrak->hint_udta.hinf.payt.rtpMapString, rtpMapBuf);
/* set the SDP media section */
sprintf(sdpBuf,
"m=video 0 RTP/AVP %u\015\012a=rtpmap:%u %s\015\012a=control:trackID=%u\015\012",
*pPayloadNumber, *pPayloadNumber, rtpMapBuf, hintTrak->tkhd.track_id);
quicktime_sdp_set(&(hintTrak->hint_udta.hnti.sdp), sdpBuf);
pMap->hintTracks[pMap->totalHintTracks] = hintTrak;
pMap->hintPositions[pMap->totalHintTracks] = 0;
pMap->totalHintTracks++;
return (pMap->totalHintTracks - 1);
}
char* quicktime_get_session_sdp(quicktime_t *file)
{
return file->moov.udta.hnti.rtp.string;
}
int quicktime_set_session_sdp(quicktime_t *file, char* sdpString)
{
return quicktime_rtp_set(&(file->moov.udta.hnti.rtp), sdpString);
}
int quicktime_add_audio_sdp(quicktime_t *file, char* sdpString, int track, int hintTrack)
{
quicktime_trak_t* hintTrak =
file->atracks[track].hintTracks[hintTrack];
quicktime_sdp_append(&(hintTrak->hint_udta.hnti.sdp), sdpString);
}
int quicktime_add_video_sdp(quicktime_t *file, char* sdpString, int track, int hintTrack)
{
quicktime_trak_t* hintTrak =
file->vtracks[track].hintTracks[hintTrack];
quicktime_sdp_append(&(hintTrak->hint_udta.hnti.sdp), sdpString);
}
static int quicktime_set_media_hint_max_rate(quicktime_t *file,
int granularity, int maxBitRate, quicktime_trak_t* hintTrak)
{
hintTrak->hint_udta.hinf.maxr.granularity = granularity;
hintTrak->hint_udta.hinf.maxr.maxBitRate = maxBitRate;
hintTrak->mdia.minf.hmhd.maxbitrate = maxBitRate;
/* Give upper bound on MP4 max bitrate for 1 minute window */
hintTrak->mdia.minf.hmhd.slidingavgbitrate =
maxBitRate * (60000 / granularity);
return 0;
}
int quicktime_set_audio_hint_max_rate(quicktime_t *file,
int granularity, int maxBitRate, int audioTrack, int hintTrack)
{
quicktime_trak_t* hintTrak =
file->atracks[audioTrack].hintTracks[hintTrack];
return quicktime_set_media_hint_max_rate(file,
granularity, maxBitRate, hintTrak);
}
int quicktime_set_video_hint_max_rate(quicktime_t *file,
int granularity, int maxBitRate, int videoTrack, int hintTrack)
{
quicktime_trak_t* hintTrak =
file->vtracks[videoTrack].hintTracks[hintTrack];
return quicktime_set_media_hint_max_rate(file,
granularity, maxBitRate, hintTrak);
}
int quicktime_set_framerate(quicktime_t *file, float framerate)
{
int i;
int new_time_scale, new_sample_duration;
new_time_scale = quicktime_get_timescale(framerate);
new_sample_duration = (int)((float)new_time_scale / framerate + 0.5);
for(i = 0; i < file->total_vtracks; i++)
{
file->vtracks[i].track->mdia.mdhd.time_scale = new_time_scale;
file->vtracks[i].track->mdia.minf.stbl.stts.table[0].sample_duration = new_sample_duration;
}
}
quicktime_trak_t* quicktime_add_track(quicktime_moov_t *moov)
{
quicktime_trak_t *trak;
trak = moov->trak[moov->total_tracks] = calloc(1, sizeof(quicktime_trak_t));
quicktime_trak_init(trak);
trak->tkhd.track_id = moov->mvhd.next_track_id;
moov->mvhd.next_track_id++;
moov->total_tracks++;
return trak;
}
/* ============================= Initialization functions */
int quicktime_init(quicktime_t *file)
{
memset(file, 0, sizeof(quicktime_t));
quicktime_mdat_init(&(file->mdat));
quicktime_moov_init(&(file->moov));
file->cpus = 1;
return 0;
}
int quicktime_delete(quicktime_t *file)
{
int i;
if(file->total_atracks)
{
for(i = 0; i < file->total_atracks; i++)
quicktime_delete_audio_map(&(file->atracks[i]));
free(file->atracks);
}
if(file->total_vtracks)
{
for(i = 0; i < file->total_vtracks; i++)
quicktime_delete_video_map(&(file->vtracks[i]));
free(file->vtracks);
}
file->total_atracks = 0;
file->total_vtracks = 0;
if(file->preload_size)
{
free(file->preload_buffer);
file->preload_size = 0;
}
quicktime_moov_delete(&(file->moov));
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -