static int rv10_write_header(AVFormatContext *ctx, int data_size, int index_pos) { RMMuxContext *rm = ctx->priv_data; ByteIOContext *s = ctx->pb; StreamInfo *stream; unsigned char *data_offset_ptr, *start_ptr; const char *desc, *mimetype; int nb_packets, packet_total_size, packet_max_size, size, packet_avg_size, i; int bit_rate, v, duration, flags, data_pos; AVMetadataTag *tag; start_ptr = s->buf_ptr; put_tag(s, ".RMF"); put_be32(s,18); /* header size */ put_be16(s,0); put_be32(s,0); put_be32(s,4 + ctx->nb_streams); /* num headers */ put_tag(s,"PROP"); put_be32(s, 50); put_be16(s, 0); packet_max_size = 0; packet_total_size = 0; nb_packets = 0; bit_rate = 0; duration = 0; for(i=0;i<ctx->nb_streams;i++) { StreamInfo *stream = &rm->streams[i]; bit_rate += stream->bit_rate; if (stream->packet_max_size > packet_max_size) packet_max_size = stream->packet_max_size; nb_packets += stream->nb_packets; packet_total_size += stream->packet_total_size; /* select maximum duration */ v = (int) (1000.0 * (float)stream->total_frames / stream->frame_rate); if (v > duration) duration = v; } put_be32(s, bit_rate); /* max bit rate */ put_be32(s, bit_rate); /* avg bit rate */ put_be32(s, packet_max_size); /* max packet size */ if (nb_packets > 0) packet_avg_size = packet_total_size / nb_packets; else packet_avg_size = 0; put_be32(s, packet_avg_size); /* avg packet size */ put_be32(s, nb_packets); /* num packets */ put_be32(s, duration); /* duration */ put_be32(s, BUFFER_DURATION); /* preroll */ put_be32(s, index_pos); /* index offset */ /* computation of data the data offset */ data_offset_ptr = s->buf_ptr; put_be32(s, 0); /* data offset : will be patched after */ put_be16(s, ctx->nb_streams); /* num streams */ flags = 1 | 2; /* save allowed & perfect play */ if (url_is_streamed(s)) flags |= 4; /* live broadcast */ put_be16(s, flags); /* comments */ put_tag(s,"CONT"); size = 4 * 2 + 10; for(i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) { tag = av_metadata_get(ctx->metadata, ff_rm_metadata[i], NULL, 0); if(tag) size += strlen(tag->value); } put_be32(s,size); put_be16(s,0); for(i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) { tag = av_metadata_get(ctx->metadata, ff_rm_metadata[i], NULL, 0); put_str(s, tag ? tag->value : ""); } for(i=0;i<ctx->nb_streams;i++) { int codec_data_size; stream = &rm->streams[i]; if (stream->enc->codec_type == AVMEDIA_TYPE_AUDIO) { desc = "The Audio Stream"; mimetype = "audio/x-pn-realaudio"; codec_data_size = 73; } else { desc = "The Video Stream"; mimetype = "video/x-pn-realvideo"; codec_data_size = 34; } put_tag(s,"MDPR"); size = 10 + 9 * 4 + strlen(desc) + strlen(mimetype) + codec_data_size; put_be32(s, size); put_be16(s, 0); put_be16(s, i); /* stream number */ put_be32(s, stream->bit_rate); /* max bit rate */ put_be32(s, stream->bit_rate); /* avg bit rate */ put_be32(s, stream->packet_max_size); /* max packet size */ if (stream->nb_packets > 0) packet_avg_size = stream->packet_total_size / stream->nb_packets; else packet_avg_size = 0; put_be32(s, packet_avg_size); /* avg packet size */ put_be32(s, 0); /* start time */ put_be32(s, BUFFER_DURATION); /* preroll */ /* duration */ if (url_is_streamed(s) || !stream->total_frames) put_be32(s, (int)(3600 * 1000)); else put_be32(s, (int)(stream->total_frames * 1000 / stream->frame_rate)); put_str8(s, desc); put_str8(s, mimetype); put_be32(s, codec_data_size); if (stream->enc->codec_type == AVMEDIA_TYPE_AUDIO) { int coded_frame_size, fscode, sample_rate; sample_rate = stream->enc->sample_rate; coded_frame_size = (stream->enc->bit_rate * stream->enc->frame_size) / (8 * sample_rate); /* audio codec info */ put_tag(s, ".ra"); put_byte(s, 0xfd); put_be32(s, 0x00040000); /* version */ put_tag(s, ".ra4"); put_be32(s, 0x01b53530); /* stream length */ put_be16(s, 4); /* unknown */ put_be32(s, 0x39); /* header size */ switch(sample_rate) { case 48000: case 24000: case 12000: fscode = 1; break; default: case 44100: case 22050: case 11025: fscode = 2; break; case 32000: case 16000: case 8000: fscode = 3; } put_be16(s, fscode); /* codec additional info, for AC-3, seems to be a frequency code */ /* special hack to compensate rounding errors... */ if (coded_frame_size == 557) coded_frame_size--; put_be32(s, coded_frame_size); /* frame length */ put_be32(s, 0x51540); /* unknown */ put_be32(s, 0x249f0); /* unknown */ put_be32(s, 0x249f0); /* unknown */ put_be16(s, 0x01); /* frame length : seems to be very important */ put_be16(s, coded_frame_size); put_be32(s, 0); /* unknown */ put_be16(s, stream->enc->sample_rate); /* sample rate */ put_be32(s, 0x10); /* unknown */ put_be16(s, stream->enc->channels); put_str8(s, "Int0"); /* codec name */ if (stream->enc->codec_tag) { put_byte(s, 4); /* tag length */ put_le32(s, stream->enc->codec_tag); } else { av_log(ctx, AV_LOG_ERROR, "Invalid codec tag\n"); return -1; } put_be16(s, 0); /* title length */ put_be16(s, 0); /* author length */ put_be16(s, 0); /* copyright length */ put_byte(s, 0); /* end of header */ } else { /* video codec info */ put_be32(s,34); /* size */ if(stream->enc->codec_id == CODEC_ID_RV10) put_tag(s,"VIDORV10"); else put_tag(s,"VIDORV20"); put_be16(s, stream->enc->width); put_be16(s, stream->enc->height); put_be16(s, (int) stream->frame_rate); /* frames per seconds ? */ put_be32(s,0); /* unknown meaning */ put_be16(s, (int) stream->frame_rate); /* unknown meaning */ put_be32(s,0); /* unknown meaning */ put_be16(s, 8); /* unknown meaning */ /* Seems to be the codec version: only use basic H263. The next versions seems to add a diffential DC coding as in MPEG... nothing new under the sun */ if(stream->enc->codec_id == CODEC_ID_RV10) put_be32(s,0x10000000); else put_be32(s,0x20103001); //put_be32(s,0x10003000); } } /* patch data offset field */ data_pos = s->buf_ptr - start_ptr; rm->data_pos = data_pos; data_offset_ptr[0] = data_pos >> 24; data_offset_ptr[1] = data_pos >> 16; data_offset_ptr[2] = data_pos >> 8; data_offset_ptr[3] = data_pos; /* data stream */ put_tag(s,"DATA"); put_be32(s,data_size + 10 + 8); put_be16(s,0); put_be32(s, nb_packets); /* number of packets */ put_be32(s,0); /* next data header */ return 0; }
static int swf_write_header(AVFormatContext *s) { SWFContext *swf = s->priv_data; ByteIOContext *pb = s->pb; PutBitContext p; uint8_t buf1[256]; int i, width, height, rate, rate_base; int version; swf->sound_samples = 0; swf->swf_frame_number = 0; swf->video_frame_number = 0; for(i=0;i<s->nb_streams;i++) { AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_AUDIO) { if (enc->codec_id == CODEC_ID_MP3) { if (!enc->frame_size) { av_log(s, AV_LOG_ERROR, "audio frame size not set\n"); return -1; } swf->audio_enc = enc; av_fifo_init(&swf->audio_fifo, AUDIO_FIFO_SIZE); } else { av_log(s, AV_LOG_ERROR, "SWF muxer only supports MP3\n"); return -1; } } else { if (enc->codec_id == CODEC_ID_VP6F || enc->codec_id == CODEC_ID_FLV1 || enc->codec_id == CODEC_ID_MJPEG) { swf->video_enc = enc; } else { av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n"); return -1; } } } if (!swf->video_enc) { /* currently, cannot work correctly if audio only */ width = 320; height = 200; rate = 10; rate_base= 1; } else { width = swf->video_enc->width; height = swf->video_enc->height; rate = swf->video_enc->time_base.den; rate_base = swf->video_enc->time_base.num; } if (!swf->audio_enc) swf->samples_per_frame = (44100. * rate_base) / rate; else swf->samples_per_frame = (swf->audio_enc->sample_rate * rate_base) / rate; put_tag(pb, "FWS"); if (!strcmp("avm2", s->oformat->name)) version = 9; else if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_VP6F) version = 8; /* version 8 and above support VP6 codec */ else if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_FLV1) version = 6; /* version 6 and above support FLV1 codec */ else version = 4; /* version 4 for mpeg audio support */ put_byte(pb, version); put_le32(pb, DUMMY_FILE_SIZE); /* dummy size (will be patched if not streamed) */ put_swf_rect(pb, 0, width * 20, 0, height * 20); put_le16(pb, (rate * 256) / rate_base); /* frame rate */ swf->duration_pos = url_ftell(pb); put_le16(pb, (uint16_t)(DUMMY_DURATION * (int64_t)rate / rate_base)); /* frame count */ /* avm2/swf v9 (also v8?) files require a file attribute tag */ if (version == 9) { put_swf_tag(s, TAG_FILEATTRIBUTES); put_le32(pb, 1<<3); /* set ActionScript v3/AVM2 flag */ put_swf_end_tag(s); } /* define a shape with the jpeg inside */ if (swf->video_enc && swf->video_enc->codec_id == CODEC_ID_MJPEG) { put_swf_tag(s, TAG_DEFINESHAPE); put_le16(pb, SHAPE_ID); /* ID of shape */ /* bounding rectangle */ put_swf_rect(pb, 0, width, 0, height); /* style info */ put_byte(pb, 1); /* one fill style */ put_byte(pb, 0x41); /* clipped bitmap fill */ put_le16(pb, BITMAP_ID); /* bitmap ID */ /* position of the bitmap */ put_swf_matrix(pb, (int)(1.0 * (1 << FRAC_BITS)), 0, 0, (int)(1.0 * (1 << FRAC_BITS)), 0, 0); put_byte(pb, 0); /* no line style */ /* shape drawing */ init_put_bits(&p, buf1, sizeof(buf1)); put_bits(&p, 4, 1); /* one fill bit */ put_bits(&p, 4, 0); /* zero line bit */ put_bits(&p, 1, 0); /* not an edge */ put_bits(&p, 5, FLAG_MOVETO | FLAG_SETFILL0); put_bits(&p, 5, 1); /* nbits */ put_bits(&p, 1, 0); /* X */ put_bits(&p, 1, 0); /* Y */ put_bits(&p, 1, 1); /* set fill style 1 */ /* draw the rectangle ! */ put_swf_line_edge(&p, width, 0); put_swf_line_edge(&p, 0, height); put_swf_line_edge(&p, -width, 0); put_swf_line_edge(&p, 0, -height); /* end of shape */ put_bits(&p, 1, 0); /* not an edge */ put_bits(&p, 5, 0); flush_put_bits(&p); put_buffer(pb, buf1, pbBufPtr(&p) - p.buf); put_swf_end_tag(s); } if (swf->audio_enc && swf->audio_enc->codec_id == CODEC_ID_MP3) { int v = 0; /* start sound */ put_swf_tag(s, TAG_STREAMHEAD2); switch(swf->audio_enc->sample_rate) { case 11025: v |= 1 << 2; break; case 22050: v |= 2 << 2; break; case 44100: v |= 3 << 2; break; default: /* not supported */ av_log(s, AV_LOG_ERROR, "swf does not support that sample rate, choose from (44100, 22050, 11025).\n"); return -1; } v |= 0x02; /* 16 bit playback */ if (swf->audio_enc->channels == 2) v |= 0x01; /* stereo playback */ put_byte(s->pb, v); v |= 0x20; /* mp3 compressed */ put_byte(s->pb, v); put_le16(s->pb, swf->samples_per_frame); /* avg samples per frame */ put_le16(s->pb, 0); put_swf_end_tag(s); } put_flush_packet(s->pb); return 0; }
static int swf_write_video(AVFormatContext *s, AVCodecContext *enc, const uint8_t *buf, int size) { SWFContext *swf = s->priv_data; ByteIOContext *pb = s->pb; /* Flash Player limit */ if (swf->swf_frame_number == 16000) av_log(enc, AV_LOG_INFO, "warning: Flash Player limit of 16000 frames reached\n"); if (enc->codec_id == CODEC_ID_VP6F || enc->codec_id == CODEC_ID_FLV1) { if (swf->video_frame_number == 0) { /* create a new video object */ put_swf_tag(s, TAG_VIDEOSTREAM); put_le16(pb, VIDEO_ID); swf->vframes_pos = url_ftell(pb); put_le16(pb, 15000); /* hard flash player limit */ put_le16(pb, enc->width); put_le16(pb, enc->height); put_byte(pb, 0); put_byte(pb,codec_get_tag(swf_codec_tags,enc->codec_id)); put_swf_end_tag(s); /* place the video object for the first time */ put_swf_tag(s, TAG_PLACEOBJECT2); put_byte(pb, 0x36); put_le16(pb, 1); put_le16(pb, VIDEO_ID); put_swf_matrix(pb, 1 << FRAC_BITS, 0, 0, 1 << FRAC_BITS, 0, 0); put_le16(pb, swf->video_frame_number); put_tag(pb, "video"); put_byte(pb, 0x00); put_swf_end_tag(s); } else { /* mark the character for update */ put_swf_tag(s, TAG_PLACEOBJECT2); put_byte(pb, 0x11); put_le16(pb, 1); put_le16(pb, swf->video_frame_number); put_swf_end_tag(s); } /* set video frame data */ put_swf_tag(s, TAG_VIDEOFRAME | TAG_LONG); put_le16(pb, VIDEO_ID); put_le16(pb, swf->video_frame_number++); put_buffer(pb, buf, size); put_swf_end_tag(s); } else if (enc->codec_id == CODEC_ID_MJPEG) { if (swf->swf_frame_number > 0) { /* remove the shape */ put_swf_tag(s, TAG_REMOVEOBJECT); put_le16(pb, SHAPE_ID); /* shape ID */ put_le16(pb, 1); /* depth */ put_swf_end_tag(s); /* free the bitmap */ put_swf_tag(s, TAG_FREECHARACTER); put_le16(pb, BITMAP_ID); put_swf_end_tag(s); } put_swf_tag(s, TAG_JPEG2 | TAG_LONG); put_le16(pb, BITMAP_ID); /* ID of the image */ /* a dummy jpeg header seems to be required */ put_be32(pb, 0xffd8ffd9); /* write the jpeg image */ put_buffer(pb, buf, size); put_swf_end_tag(s); /* draw the shape */ put_swf_tag(s, TAG_PLACEOBJECT); put_le16(pb, SHAPE_ID); /* shape ID */ put_le16(pb, 1); /* depth */ put_swf_matrix(pb, 20 << FRAC_BITS, 0, 0, 20 << FRAC_BITS, 0, 0); put_swf_end_tag(s); } swf->swf_frame_number++; /* streaming sound always should be placed just before showframe tags */ if (swf->audio_enc && av_fifo_size(&swf->audio_fifo)) { int frame_size = av_fifo_size(&swf->audio_fifo); put_swf_tag(s, TAG_STREAMBLOCK | TAG_LONG); put_le16(pb, swf->sound_samples); put_le16(pb, 0); // seek samples av_fifo_generic_read(&swf->audio_fifo, frame_size, &put_buffer, pb); put_swf_end_tag(s); /* update FIFO */ swf->sound_samples = 0; } /* output the frame */ put_swf_tag(s, TAG_SHOWFRAME); put_swf_end_tag(s); put_flush_packet(s->pb); return 0; }
static void free_cmd(struct nullb_cmd *cmd) { put_tag(cmd->nq, cmd->tag); }
static int avi_write_header(AVFormatContext *s) { AVIContext *avi = s->priv_data; ByteIOContext *pb = &s->pb; int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; AVCodecContext *stream, *video_enc; offset_t list1, list2, strh, strf; /* header list */ avi->riff_id = 0; list1 = avi_start_new_riff(avi, pb, "AVI ", "hdrl"); /* avi header */ put_tag(pb, "avih"); put_le32(pb, 14 * 4); bitrate = 0; video_enc = NULL; for(n=0;n<s->nb_streams;n++) { stream = s->streams[n]->codec; bitrate += stream->bit_rate; if (stream->codec_type == CODEC_TYPE_VIDEO) video_enc = stream; } nb_frames = 0; if(video_enc){ put_le32(pb, (uint32_t)(int64_t_C(1000000) * video_enc->time_base.num / video_enc->time_base.den)); } else { put_le32(pb, 0); } put_le32(pb, bitrate / 8); /* XXX: not quite exact */ put_le32(pb, 0); /* padding */ if (url_is_streamed(pb)) put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ else put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */ put_le32(pb, nb_frames); /* nb frames, filled later */ put_le32(pb, 0); /* initial frame */ put_le32(pb, s->nb_streams); /* nb streams */ put_le32(pb, 1024 * 1024); /* suggested buffer size */ if(video_enc){ put_le32(pb, video_enc->width); put_le32(pb, video_enc->height); } else { put_le32(pb, 0); put_le32(pb, 0); } put_le32(pb, 0); /* reserved */ put_le32(pb, 0); /* reserved */ put_le32(pb, 0); /* reserved */ put_le32(pb, 0); /* reserved */ /* stream list */ for(i=0;i<n;i++) { list2 = start_tag(pb, "LIST"); put_tag(pb, "strl"); stream = s->streams[i]->codec; /* FourCC should really be set by the codec itself */ if (! stream->codec_tag) { stream->codec_tag = codec_get_bmp_tag(stream->codec_id); } /* stream generic header */ strh = start_tag(pb, "strh"); switch(stream->codec_type) { case CODEC_TYPE_VIDEO: put_tag(pb, "vids"); break; case CODEC_TYPE_AUDIO: put_tag(pb, "auds"); break; // case CODEC_TYPE_TEXT : put_tag(pb, "txts"); break; case CODEC_TYPE_DATA : put_tag(pb, "dats"); break; } if(stream->codec_type == CODEC_TYPE_VIDEO) put_le32(pb, stream->codec_tag); else put_le32(pb, 1); put_le32(pb, 0); /* flags */ put_le16(pb, 0); /* priority */ put_le16(pb, 0); /* language */ put_le32(pb, 0); /* initial frame */ ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); put_le32(pb, au_scale); /* scale */ put_le32(pb, au_byterate); /* rate */ av_set_pts_info(s->streams[i], 64, au_scale, au_byterate); put_le32(pb, 0); /* start */ avi->frames_hdr_strm[i] = url_ftell(pb); /* remember this offset to fill later */ if (url_is_streamed(pb)) put_le32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ else put_le32(pb, 0); /* length, XXX: filled later */ /* suggested buffer size */ //FIXME set at the end to largest chunk if(stream->codec_type == CODEC_TYPE_VIDEO) put_le32(pb, 1024 * 1024); else if(stream->codec_type == CODEC_TYPE_AUDIO) put_le32(pb, 12 * 1024); else put_le32(pb, 0); put_le32(pb, -1); /* quality */ put_le32(pb, au_ssize); /* sample size */ put_le32(pb, 0); put_le16(pb, stream->width); put_le16(pb, stream->height); end_tag(pb, strh); if(stream->codec_type != CODEC_TYPE_DATA){ strf = start_tag(pb, "strf"); switch(stream->codec_type) { case CODEC_TYPE_VIDEO: put_bmp_header(pb, stream, codec_bmp_tags, 0); break; case CODEC_TYPE_AUDIO: if (put_wav_header(pb, stream) < 0) { av_free(avi); return -1; } break; default: return -1; } end_tag(pb, strf); } if (!url_is_streamed(pb)) { unsigned char tag[5]; int j; /* Starting to lay out AVI OpenDML master index. * We want to make it JUNK entry for now, since we'd * like to get away without making AVI an OpenDML one * for compatibility reasons. */ avi->indexes[i].entry = avi->indexes[i].ents_allocated = 0; avi->indexes[i].indx_start = start_tag(pb, "JUNK"); put_le16(pb, 4); /* wLongsPerEntry */ put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); /* dwChunkId */ put_le64(pb, 0); /* dwReserved[3] put_le32(pb, 0); Must be 0. */ for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) put_le64(pb, 0); end_tag(pb, avi->indexes[i].indx_start); } end_tag(pb, list2); } if (!url_is_streamed(pb)) { /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ avi->odml_list = start_tag(pb, "JUNK"); put_tag(pb, "odml"); put_tag(pb, "dmlh"); put_le32(pb, 248); for (i = 0; i < 248; i+= 4) put_le32(pb, 0); end_tag(pb, avi->odml_list); } end_tag(pb, list1); list2 = start_tag(pb, "LIST"); put_tag(pb, "INFO"); avi_write_info_tag(pb, "INAM", s->title); avi_write_info_tag(pb, "IART", s->author); avi_write_info_tag(pb, "ICOP", s->copyright); avi_write_info_tag(pb, "ICMT", s->comment); avi_write_info_tag(pb, "IPRD", s->album); avi_write_info_tag(pb, "IGNR", s->genre); if (s->track) { char str_track[4]; snprintf(str_track, 4, "%d", s->track); avi_write_info_tag(pb, "IPRT", str_track); } if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); end_tag(pb, list2); /* some padding for easier tag editing */ list2 = start_tag(pb, "JUNK"); for (i = 0; i < 1016; i += 4) put_le32(pb, 0); end_tag(pb, list2); avi->movi_list = start_tag(pb, "LIST"); put_tag(pb, "movi"); put_flush_packet(pb); return 0; }
static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine) { #ifdef TARGET_WORDS_BIGENDIAN int be = 1; #else int be = 0; #endif MemoryRegion *system_memory = get_system_memory(); XtensaCPU *cpu = NULL; CPUXtensaState *env = NULL; MemoryRegion *system_io; DriveInfo *dinfo; pflash_t *flash = NULL; QemuOpts *machine_opts = qemu_get_machine_opts(); const char *kernel_filename = qemu_opt_get(machine_opts, "kernel"); const char *kernel_cmdline = qemu_opt_get(machine_opts, "append"); const char *dtb_filename = qemu_opt_get(machine_opts, "dtb"); const char *initrd_filename = qemu_opt_get(machine_opts, "initrd"); const unsigned system_io_size = 224 * 1024 * 1024; int n; for (n = 0; n < smp_cpus; n++) { cpu = XTENSA_CPU(cpu_create(machine->cpu_type)); env = &cpu->env; env->sregs[PRID] = n; qemu_register_reset(xtfpga_reset, cpu); /* Need MMU initialized prior to ELF loading, * so that ELF gets loaded into virtual addresses */ cpu_reset(CPU(cpu)); } if (env) { XtensaMemory sysram = env->config->sysram; sysram.location[0].size = machine->ram_size; xtensa_create_memory_regions(&env->config->instrom, "xtensa.instrom", system_memory); xtensa_create_memory_regions(&env->config->instram, "xtensa.instram", system_memory); xtensa_create_memory_regions(&env->config->datarom, "xtensa.datarom", system_memory); xtensa_create_memory_regions(&env->config->dataram, "xtensa.dataram", system_memory); xtensa_create_memory_regions(&sysram, "xtensa.sysram", system_memory); } system_io = g_malloc(sizeof(*system_io)); memory_region_init_io(system_io, NULL, &xtfpga_io_ops, NULL, "xtfpga.io", system_io_size); memory_region_add_subregion(system_memory, board->io[0], system_io); if (board->io[1]) { MemoryRegion *io = g_malloc(sizeof(*io)); memory_region_init_alias(io, NULL, "xtfpga.io.cached", system_io, 0, system_io_size); memory_region_add_subregion(system_memory, board->io[1], io); } xtfpga_fpga_init(system_io, 0x0d020000); if (nd_table[0].used) { xtfpga_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000, xtensa_get_extint(env, 1), nd_table); } if (!serial_hds[0]) { serial_hds[0] = qemu_chr_new("serial0", "null"); } serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0), 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); dinfo = drive_get(IF_PFLASH, 0, 0); if (dinfo) { flash = xtfpga_flash_init(system_io, board, dinfo, be); } /* Use presence of kernel file name as 'boot from SRAM' switch. */ if (kernel_filename) { uint32_t entry_point = env->pc; size_t bp_size = 3 * get_tag_size(0); /* first/last and memory tags */ uint32_t tagptr = env->config->sysrom.location[0].addr + board->sram_size; uint32_t cur_tagptr; BpMemInfo memory_location = { .type = tswap32(MEMORY_TYPE_CONVENTIONAL), .start = tswap32(env->config->sysram.location[0].addr), .end = tswap32(env->config->sysram.location[0].addr + machine->ram_size), }; uint32_t lowmem_end = machine->ram_size < 0x08000000 ? machine->ram_size : 0x08000000; uint32_t cur_lowmem = QEMU_ALIGN_UP(lowmem_end / 2, 4096); lowmem_end += env->config->sysram.location[0].addr; cur_lowmem += env->config->sysram.location[0].addr; xtensa_create_memory_regions(&env->config->sysrom, "xtensa.sysrom", system_memory); if (kernel_cmdline) { bp_size += get_tag_size(strlen(kernel_cmdline) + 1); } if (dtb_filename) { bp_size += get_tag_size(sizeof(uint32_t)); } if (initrd_filename) { bp_size += get_tag_size(sizeof(BpMemInfo)); } /* Put kernel bootparameters to the end of that SRAM */ tagptr = (tagptr - bp_size) & ~0xff; cur_tagptr = put_tag(tagptr, BP_TAG_FIRST, 0, NULL); cur_tagptr = put_tag(cur_tagptr, BP_TAG_MEMORY, sizeof(memory_location), &memory_location); if (kernel_cmdline) { cur_tagptr = put_tag(cur_tagptr, BP_TAG_COMMAND_LINE, strlen(kernel_cmdline) + 1, kernel_cmdline); } #ifdef CONFIG_FDT if (dtb_filename) { int fdt_size; void *fdt = load_device_tree(dtb_filename, &fdt_size); uint32_t dtb_addr = tswap32(cur_lowmem); if (!fdt) { error_report("could not load DTB '%s'", dtb_filename); exit(EXIT_FAILURE); } cpu_physical_memory_write(cur_lowmem, fdt, fdt_size); cur_tagptr = put_tag(cur_tagptr, BP_TAG_FDT, sizeof(dtb_addr), &dtb_addr); cur_lowmem = QEMU_ALIGN_UP(cur_lowmem + fdt_size, 4096); } #else if (dtb_filename) { error_report("could not load DTB '%s': " "FDT support is not configured in QEMU", dtb_filename); exit(EXIT_FAILURE); } #endif if (initrd_filename) { BpMemInfo initrd_location = { 0 }; int initrd_size = load_ramdisk(initrd_filename, cur_lowmem, lowmem_end - cur_lowmem); if (initrd_size < 0) { initrd_size = load_image_targphys(initrd_filename, cur_lowmem, lowmem_end - cur_lowmem); } if (initrd_size < 0) { error_report("could not load initrd '%s'", initrd_filename); exit(EXIT_FAILURE); } initrd_location.start = tswap32(cur_lowmem); initrd_location.end = tswap32(cur_lowmem + initrd_size); cur_tagptr = put_tag(cur_tagptr, BP_TAG_INITRD, sizeof(initrd_location), &initrd_location); cur_lowmem = QEMU_ALIGN_UP(cur_lowmem + initrd_size, 4096); } cur_tagptr = put_tag(cur_tagptr, BP_TAG_LAST, 0, NULL); env->regs[2] = tagptr; uint64_t elf_entry; uint64_t elf_lowaddr; int success = load_elf(kernel_filename, translate_phys_addr, cpu, &elf_entry, &elf_lowaddr, NULL, be, EM_XTENSA, 0, 0); if (success > 0) { entry_point = elf_entry; } else { hwaddr ep; int is_linux; success = load_uimage(kernel_filename, &ep, NULL, &is_linux, translate_phys_addr, cpu); if (success > 0 && is_linux) { entry_point = ep; } else { error_report("could not load kernel '%s'", kernel_filename); exit(EXIT_FAILURE); } } if (entry_point != env->pc) { uint8_t boot[] = { #ifdef TARGET_WORDS_BIGENDIAN 0x60, 0x00, 0x08, /* j 1f */ 0x00, /* .literal_position */ 0x00, 0x00, 0x00, 0x00, /* .literal entry_pc */ 0x00, 0x00, 0x00, 0x00, /* .literal entry_a2 */ /* 1: */ 0x10, 0xff, 0xfe, /* l32r a0, entry_pc */ 0x12, 0xff, 0xfe, /* l32r a2, entry_a2 */ 0x0a, 0x00, 0x00, /* jx a0 */ #else 0x06, 0x02, 0x00, /* j 1f */ 0x00, /* .literal_position */ 0x00, 0x00, 0x00, 0x00, /* .literal entry_pc */ 0x00, 0x00, 0x00, 0x00, /* .literal entry_a2 */ /* 1: */ 0x01, 0xfe, 0xff, /* l32r a0, entry_pc */ 0x21, 0xfe, 0xff, /* l32r a2, entry_a2 */ 0xa0, 0x00, 0x00, /* jx a0 */ #endif }; uint32_t entry_pc = tswap32(entry_point); uint32_t entry_a2 = tswap32(tagptr); memcpy(boot + 4, &entry_pc, sizeof(entry_pc)); memcpy(boot + 8, &entry_a2, sizeof(entry_a2)); cpu_physical_memory_write(env->pc, boot, sizeof(boot)); } } else { if (flash) { MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash); MemoryRegion *flash_io = g_malloc(sizeof(*flash_io)); uint32_t size = env->config->sysrom.location[0].size; if (board->flash->size - board->flash->boot_base < size) { size = board->flash->size - board->flash->boot_base; } memory_region_init_alias(flash_io, NULL, "xtfpga.flash", flash_mr, board->flash->boot_base, size); memory_region_add_subregion(system_memory, env->config->sysrom.location[0].addr, flash_io); } else { xtensa_create_memory_regions(&env->config->sysrom, "xtensa.sysrom", system_memory); } } }
static void lx_init(const LxBoardDesc *board, ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model) { #ifdef TARGET_WORDS_BIGENDIAN int be = 1; #else int be = 0; #endif MemoryRegion *system_memory = get_system_memory(); CPUXtensaState *env = NULL; MemoryRegion *ram, *rom, *system_io; DriveInfo *dinfo; pflash_t *flash = NULL; int n; if (!cpu_model) { cpu_model = "dc232b"; } for (n = 0; n < smp_cpus; n++) { env = cpu_init(cpu_model); if (!env) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } env->sregs[PRID] = n; qemu_register_reset(lx60_reset, env); /* Need MMU initialized prior to ELF loading, * so that ELF gets loaded into virtual addresses */ cpu_state_reset(env); } ram = g_malloc(sizeof(*ram)); memory_region_init_ram(ram, "lx60.dram", ram_size); vmstate_register_ram_global(ram); memory_region_add_subregion(system_memory, 0, ram); system_io = g_malloc(sizeof(*system_io)); memory_region_init(system_io, "lx60.io", 224 * 1024 * 1024); memory_region_add_subregion(system_memory, 0xf0000000, system_io); lx60_fpga_init(system_io, 0x0d020000); if (nd_table[0].vlan) { lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000, xtensa_get_extint(env, 1), nd_table); } if (!serial_hds[0]) { serial_hds[0] = qemu_chr_new("serial0", "null", NULL); } serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0), 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); dinfo = drive_get(IF_PFLASH, 0, 0); if (dinfo) { flash = pflash_cfi01_register(0xf8000000, NULL, "lx60.io.flash", board->flash_size, dinfo->bdrv, board->flash_sector_size, board->flash_size / board->flash_sector_size, 4, 0x0000, 0x0000, 0x0000, 0x0000, be); if (flash == NULL) { fprintf(stderr, "Unable to mount pflash\n"); exit(1); } } /* Use presence of kernel file name as 'boot from SRAM' switch. */ if (kernel_filename) { rom = g_malloc(sizeof(*rom)); memory_region_init_ram(rom, "lx60.sram", board->sram_size); vmstate_register_ram_global(rom); memory_region_add_subregion(system_memory, 0xfe000000, rom); /* Put kernel bootparameters to the end of that SRAM */ if (kernel_cmdline) { size_t cmdline_size = strlen(kernel_cmdline) + 1; size_t bp_size = sizeof(BpTag[4]) + cmdline_size; uint32_t tagptr = (0xfe000000 + board->sram_size - bp_size) & ~0xff; env->regs[2] = tagptr; tagptr = put_tag(tagptr, 0x7b0b, 0, NULL); if (cmdline_size > 1) { tagptr = put_tag(tagptr, 0x1001, cmdline_size, kernel_cmdline); } tagptr = put_tag(tagptr, 0x7e0b, 0, NULL); } uint64_t elf_entry; uint64_t elf_lowaddr; int success = load_elf(kernel_filename, translate_phys_addr, env, &elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0); if (success > 0) { env->pc = elf_entry; } } else { if (flash) { MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash); MemoryRegion *flash_io = g_malloc(sizeof(*flash_io)); memory_region_init_alias(flash_io, "lx60.flash", flash_mr, 0, board->flash_size); memory_region_add_subregion(system_memory, 0xfe000000, flash_io); } } }
static int aiff_write_header(AVFormatContext *s) { AIFFOutputContext *aiff = s->priv_data; ByteIOContext *pb = s->pb; AVCodecContext *enc = s->streams[0]->codec; AVExtFloat sample_rate; int aifc = 0; /* First verify if format is ok */ if (!enc->codec_tag) return -1; if (enc->codec_tag != MKTAG('N','O','N','E')) aifc = 1; /* FORM AIFF header */ put_tag(pb, "FORM"); aiff->form = url_ftell(pb); put_be32(pb, 0); /* file length */ put_tag(pb, aifc ? "AIFC" : "AIFF"); if (aifc) { // compressed audio enc->bits_per_coded_sample = 16; if (!enc->block_align) { av_log(s, AV_LOG_ERROR, "block align not set\n"); return -1; } /* Version chunk */ put_tag(pb, "FVER"); put_be32(pb, 4); put_be32(pb, 0xA2805140); } /* Common chunk */ put_tag(pb, "COMM"); put_be32(pb, aifc ? 24 : 18); /* size */ put_be16(pb, enc->channels); /* Number of channels */ aiff->frames = url_ftell(pb); put_be32(pb, 0); /* Number of frames */ if (!enc->bits_per_coded_sample) enc->bits_per_coded_sample = av_get_bits_per_sample(enc->codec_id); if (!enc->bits_per_coded_sample) { av_log(s, AV_LOG_ERROR, "could not compute bits per sample\n"); return -1; } if (!enc->block_align) enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3; put_be16(pb, enc->bits_per_coded_sample); /* Sample size */ sample_rate = av_dbl2ext((double)enc->sample_rate); put_buffer(pb, (uint8_t*)&sample_rate, sizeof(sample_rate)); if (aifc) { put_le32(pb, enc->codec_tag); put_be16(pb, 0); } /* Sound data chunk */ put_tag(pb, "SSND"); aiff->ssnd = url_ftell(pb); /* Sound chunk size */ put_be32(pb, 0); /* Sound samples data size */ put_be32(pb, 0); /* Data offset */ put_be32(pb, 0); /* Block-size (block align) */ av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); /* Data is starting here */ put_flush_packet(pb); return 0; }
static int flv_write_header(AVFormatContext *s) { ByteIOContext *pb = s->pb; FLVContext *flv = s->priv_data; AVCodecContext *audio_enc = NULL, *video_enc = NULL; int i; double framerate = 0.0; int metadata_size_pos, data_size; for(i=0; i<s->nb_streams; i++){ AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_type == AVMEDIA_TYPE_VIDEO) { if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) { framerate = av_q2d(s->streams[i]->r_frame_rate); } else { framerate = 1/av_q2d(s->streams[i]->codec->time_base); } video_enc = enc; if(enc->codec_tag == 0) { av_log(enc, AV_LOG_ERROR, "video codec not compatible with flv\n"); return -1; } } else { audio_enc = enc; if(get_audio_flags(enc)<0) return -1; } av_set_pts_info(s->streams[i], 32, 1, 1000); /* 32 bit pts in ms */ } put_tag(pb,"FLV"); put_byte(pb,1); put_byte(pb, FLV_HEADER_FLAG_HASAUDIO * !!audio_enc + FLV_HEADER_FLAG_HASVIDEO * !!video_enc); put_be32(pb,9); put_be32(pb,0); for(i=0; i<s->nb_streams; i++){ if(s->streams[i]->codec->codec_tag == 5){ put_byte(pb,8); // message type put_be24(pb,0); // include flags put_be24(pb,0); // time stamp put_be32(pb,0); // reserved put_be32(pb,11); // size flv->reserved=5; } } /* write meta_tag */ put_byte(pb, 18); // tag type META metadata_size_pos= url_ftell(pb); put_be24(pb, 0); // size of data part (sum of all parts below) put_be24(pb, 0); // time stamp put_be32(pb, 0); // reserved /* now data of data_size size */ /* first event name as a string */ put_byte(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ put_byte(pb, AMF_DATA_TYPE_MIXEDARRAY); put_be32(pb, 5*!!video_enc + 5*!!audio_enc + 2); // +2 for duration and file size put_amf_string(pb, "duration"); flv->duration_offset= url_ftell(pb); put_amf_double(pb, s->duration / AV_TIME_BASE); // fill in the guessed duration, it'll be corrected later if incorrect if(video_enc){ put_amf_string(pb, "width"); put_amf_double(pb, video_enc->width); put_amf_string(pb, "height"); put_amf_double(pb, video_enc->height); put_amf_string(pb, "videodatarate"); put_amf_double(pb, video_enc->bit_rate / 1024.0); put_amf_string(pb, "framerate"); put_amf_double(pb, framerate); put_amf_string(pb, "videocodecid"); put_amf_double(pb, video_enc->codec_tag); } if(audio_enc){ put_amf_string(pb, "audiodatarate"); put_amf_double(pb, audio_enc->bit_rate / 1024.0); put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, audio_enc->sample_rate); put_amf_string(pb, "audiosamplesize"); put_amf_double(pb, audio_enc->codec_id == CODEC_ID_PCM_U8 ? 8 : 16); put_amf_string(pb, "stereo"); put_amf_bool(pb, audio_enc->channels == 2); put_amf_string(pb, "audiocodecid"); put_amf_double(pb, audio_enc->codec_tag); } put_amf_string(pb, "filesize"); flv->filesize_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write put_amf_string(pb, ""); put_byte(pb, AMF_END_OF_OBJECT); /* write total size of tag */ data_size= url_ftell(pb) - metadata_size_pos - 10; url_fseek(pb, metadata_size_pos, SEEK_SET); put_be24(pb, data_size); url_fseek(pb, data_size + 10 - 3, SEEK_CUR); put_be32(pb, data_size + 11); for (i = 0; i < s->nb_streams; i++) { AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_id == CODEC_ID_AAC || enc->codec_id == CODEC_ID_H264) { int64_t pos; put_byte(pb, enc->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); put_be24(pb, 0); // size patched later put_be24(pb, 0); // ts put_byte(pb, 0); // ts ext put_be24(pb, 0); // streamid pos = url_ftell(pb); if (enc->codec_id == CODEC_ID_AAC) { put_byte(pb, get_audio_flags(enc)); put_byte(pb, 0); // AAC sequence header put_buffer(pb, enc->extradata, enc->extradata_size); } else { put_byte(pb, enc->codec_tag | FLV_FRAME_KEY); // flags put_byte(pb, 0); // AVC sequence header put_be24(pb, 0); // composition time ff_isom_write_avcc(pb, enc->extradata, enc->extradata_size); } data_size = url_ftell(pb) - pos; url_fseek(pb, -data_size - 10, SEEK_CUR); put_be24(pb, data_size); url_fseek(pb, data_size + 10 - 3, SEEK_CUR); put_be32(pb, data_size + 11); // previous tag size } } return 0; }
offset_t start_tag(ByteIOContext *pb, const char *tag) { put_tag(pb, tag); put_le32(pb, 0); return url_ftell(pb); }
static int avi_write_idx1(AVFormatContext *s) { ByteIOContext *pb = &s->pb; AVIContext *avi = s->priv_data; offset_t file_size, idx_chunk; int i, n, nb_frames, au_byterate, au_ssize, au_scale; AVCodecContext *stream; unsigned char tag[5]; if (!url_is_streamed(pb)) { AVIIentry* ie = 0, *tie; int entry[MAX_STREAMS]; int empty, stream_id = -1; idx_chunk = start_tag(pb, "idx1"); memset(&entry[0], 0, sizeof(entry)); do { empty = 1; for (i=0; i<s->nb_streams; i++) { if (avi->indexes[i].entry <= entry[i]) continue; tie = avi_get_ientry(&avi->indexes[i], entry[i]); if (empty || tie->pos < ie->pos) { ie = tie; stream_id = i; } empty = 0; } if (!empty) { avi_stream2fourcc(&tag[0], stream_id, s->streams[stream_id]->codec->codec_type); put_tag(pb, &tag[0]); put_le32(pb, ie->flags); put_le32(pb, ie->pos); put_le32(pb, ie->len); entry[stream_id]++; } } while (!empty); end_tag(pb, idx_chunk); /* Fill in frame/sample counters */ file_size = url_ftell(pb); nb_frames = 0; for(n=0;n<s->nb_streams;n++) { assert(avi->frames_hdr_strm[n]); stream = s->streams[n]->codec; url_fseek(pb, avi->frames_hdr_strm[n], SEEK_SET); ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); if (au_ssize == 0) { put_le32(pb, avi->packet_count[n]); } else { put_le32(pb, avi->audio_strm_length[n] / au_ssize); } if(stream->codec_type == CODEC_TYPE_VIDEO) nb_frames = FFMAX(nb_frames, avi->packet_count[n]); } assert(avi->frames_hdr_all); url_fseek(pb, avi->frames_hdr_all, SEEK_SET); put_le32(pb, nb_frames); url_fseek(pb, file_size, SEEK_SET); } return 0; }
static int avi_write_header(AVFormatContext *s) { AVIContext *avi = s->priv_data; ByteIOContext *pb = s->pb; int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; AVCodecContext *stream, *video_enc; int64_t list1, list2, strh, strf; AVMetadataTag *t = NULL; for(n=0;n<s->nb_streams;n++) { s->streams[n]->priv_data= av_mallocz(sizeof(AVIStream)); if(!s->streams[n]->priv_data) return AVERROR(ENOMEM); } /* header list */ avi->riff_id = 0; list1 = avi_start_new_riff(s, pb, "AVI ", "hdrl"); /* avi header */ put_tag(pb, "avih"); put_le32(pb, 14 * 4); bitrate = 0; video_enc = NULL; for(n=0;n<s->nb_streams;n++) { stream = s->streams[n]->codec; bitrate += stream->bit_rate; if (stream->codec_type == AVMEDIA_TYPE_VIDEO) video_enc = stream; } nb_frames = 0; if(video_enc){ put_le32(pb, (uint32_t)(INT64_C(1000000) * video_enc->time_base.num / video_enc->time_base.den)); } else { put_le32(pb, 0); } put_le32(pb, bitrate / 8); /* XXX: not quite exact */ put_le32(pb, 0); /* padding */ if (url_is_streamed(pb)) put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_ISINTERLEAVED); /* flags */ else put_le32(pb, AVIF_TRUSTCKTYPE | AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* flags */ avi->frames_hdr_all = url_ftell(pb); /* remember this offset to fill later */ put_le32(pb, nb_frames); /* nb frames, filled later */ put_le32(pb, 0); /* initial frame */ put_le32(pb, s->nb_streams); /* nb streams */ put_le32(pb, 1024 * 1024); /* suggested buffer size */ if(video_enc){ put_le32(pb, video_enc->width); put_le32(pb, video_enc->height); } else { put_le32(pb, 0); put_le32(pb, 0); } put_le32(pb, 0); /* reserved */ put_le32(pb, 0); /* reserved */ put_le32(pb, 0); /* reserved */ put_le32(pb, 0); /* reserved */ /* stream list */ for(i=0;i<n;i++) { AVIStream *avist= s->streams[i]->priv_data; list2 = ff_start_tag(pb, "LIST"); put_tag(pb, "strl"); stream = s->streams[i]->codec; /* stream generic header */ strh = ff_start_tag(pb, "strh"); switch(stream->codec_type) { case AVMEDIA_TYPE_SUBTITLE: // XSUB subtitles behave like video tracks, other subtitles // are not (yet) supported. if (stream->codec_id != CODEC_ID_XSUB) { av_log(s, AV_LOG_ERROR, "Subtitle streams other than DivX XSUB are not supported by the AVI muxer.\n"); return AVERROR_PATCHWELCOME; } case AVMEDIA_TYPE_VIDEO: put_tag(pb, "vids"); break; case AVMEDIA_TYPE_AUDIO: put_tag(pb, "auds"); break; // case AVMEDIA_TYPE_TEXT : put_tag(pb, "txts"); break; case AVMEDIA_TYPE_DATA : put_tag(pb, "dats"); break; } if(stream->codec_type == AVMEDIA_TYPE_VIDEO || stream->codec_id == CODEC_ID_XSUB) put_le32(pb, stream->codec_tag); else put_le32(pb, 1); put_le32(pb, 0); /* flags */ put_le16(pb, 0); /* priority */ put_le16(pb, 0); /* language */ put_le32(pb, 0); /* initial frame */ ff_parse_specific_params(stream, &au_byterate, &au_ssize, &au_scale); put_le32(pb, au_scale); /* scale */ put_le32(pb, au_byterate); /* rate */ av_set_pts_info(s->streams[i], 64, au_scale, au_byterate); put_le32(pb, 0); /* start */ avist->frames_hdr_strm = url_ftell(pb); /* remember this offset to fill later */ if (url_is_streamed(pb)) put_le32(pb, AVI_MAX_RIFF_SIZE); /* FIXME: this may be broken, but who cares */ else put_le32(pb, 0); /* length, XXX: filled later */ /* suggested buffer size */ //FIXME set at the end to largest chunk if(stream->codec_type == AVMEDIA_TYPE_VIDEO) put_le32(pb, 1024 * 1024); else if(stream->codec_type == AVMEDIA_TYPE_AUDIO) put_le32(pb, 12 * 1024); else put_le32(pb, 0); put_le32(pb, -1); /* quality */ put_le32(pb, au_ssize); /* sample size */ put_le32(pb, 0); put_le16(pb, stream->width); put_le16(pb, stream->height); ff_end_tag(pb, strh); if(stream->codec_type != AVMEDIA_TYPE_DATA){ strf = ff_start_tag(pb, "strf"); switch(stream->codec_type) { case AVMEDIA_TYPE_SUBTITLE: // XSUB subtitles behave like video tracks, other subtitles // are not (yet) supported. if (stream->codec_id != CODEC_ID_XSUB) break; case AVMEDIA_TYPE_VIDEO: ff_put_bmp_header(pb, stream, ff_codec_bmp_tags, 0); break; case AVMEDIA_TYPE_AUDIO: if (ff_put_wav_header(pb, stream) < 0) { return -1; } break; default: return -1; } ff_end_tag(pb, strf); if ((t = av_metadata_get(s->streams[i]->metadata, "title", NULL, 0))) { avi_write_info_tag(s->pb, "strn", t->value); t = NULL; } } if (!url_is_streamed(pb)) { unsigned char tag[5]; int j; /* Starting to lay out AVI OpenDML master index. * We want to make it JUNK entry for now, since we'd * like to get away without making AVI an OpenDML one * for compatibility reasons. */ avist->indexes.entry = avist->indexes.ents_allocated = 0; avist->indexes.indx_start = ff_start_tag(pb, "JUNK"); put_le16(pb, 4); /* wLongsPerEntry */ put_byte(pb, 0); /* bIndexSubType (0 == frame index) */ put_byte(pb, 0); /* bIndexType (0 == AVI_INDEX_OF_INDEXES) */ put_le32(pb, 0); /* nEntriesInUse (will fill out later on) */ put_tag(pb, avi_stream2fourcc(&tag[0], i, stream->codec_type)); /* dwChunkId */ put_le64(pb, 0); /* dwReserved[3] put_le32(pb, 0); Must be 0. */ for (j=0; j < AVI_MASTER_INDEX_SIZE * 2; j++) put_le64(pb, 0); ff_end_tag(pb, avist->indexes.indx_start); } if( stream->codec_type == AVMEDIA_TYPE_VIDEO && s->streams[i]->sample_aspect_ratio.num>0 && s->streams[i]->sample_aspect_ratio.den>0){ int vprp= ff_start_tag(pb, "vprp"); AVRational dar = av_mul_q(s->streams[i]->sample_aspect_ratio, (AVRational){stream->width, stream->height}); int num, den; av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); put_le32(pb, 0); //video format = unknown put_le32(pb, 0); //video standard= unknown put_le32(pb, lrintf(1.0/av_q2d(stream->time_base))); put_le32(pb, stream->width ); put_le32(pb, stream->height); put_le16(pb, den); put_le16(pb, num); put_le32(pb, stream->width ); put_le32(pb, stream->height); put_le32(pb, 1); //progressive FIXME put_le32(pb, stream->height); put_le32(pb, stream->width ); put_le32(pb, stream->height); put_le32(pb, stream->width ); put_le32(pb, 0); put_le32(pb, 0); put_le32(pb, 0); put_le32(pb, 0); ff_end_tag(pb, vprp); } ff_end_tag(pb, list2); } if (!url_is_streamed(pb)) { /* AVI could become an OpenDML one, if it grows beyond 2Gb range */ avi->odml_list = ff_start_tag(pb, "JUNK"); put_tag(pb, "odml"); put_tag(pb, "dmlh"); put_le32(pb, 248); for (i = 0; i < 248; i+= 4) put_le32(pb, 0); ff_end_tag(pb, avi->odml_list); } ff_end_tag(pb, list1); list2 = ff_start_tag(pb, "LIST"); put_tag(pb, "INFO"); ff_metadata_conv(&s->metadata, ff_avi_metadata_conv, NULL); for (i = 0; *ff_avi_tags[i]; i++) { if ((t = av_metadata_get(s->metadata, ff_avi_tags[i], NULL, AV_METADATA_MATCH_CASE))) avi_write_info_tag(s->pb, t->key, t->value); } ff_end_tag(pb, list2); /* some padding for easier tag editing */ list2 = ff_start_tag(pb, "JUNK"); for (i = 0; i < 1016; i += 4) put_le32(pb, 0); ff_end_tag(pb, list2); avi->movi_list = ff_start_tag(pb, "LIST"); put_tag(pb, "movi"); put_flush_packet(pb); return 0; }
static int flv_write_header(AVFormatContext *s) { ByteIOContext *pb = s->pb; FLVContext *flv = s->priv_data; int i, width, height, samplerate, samplesize, channels, audiocodecid, videocodecid; double framerate = 0.0; int metadata_size_pos, data_size; flv->hasAudio = 0; flv->hasVideo = 0; for(i=0; i<s->nb_streams; i++){ AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_VIDEO) { width = enc->width; height = enc->height; if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) { framerate = av_q2d(s->streams[i]->r_frame_rate); } else { framerate = 1/av_q2d(s->streams[i]->codec->time_base); } flv->hasVideo=1; videocodecid = enc->codec_tag; if(videocodecid == 0) { av_log(enc, AV_LOG_ERROR, "video codec not compatible with flv\n"); return -1; } } else { flv->hasAudio=1; samplerate = enc->sample_rate; channels = enc->channels; audiocodecid = enc->codec_tag; samplesize = (enc->codec_id == CODEC_ID_PCM_S8) ? 8 : 16; if(get_audio_flags(enc)<0) return -1; } av_set_pts_info(s->streams[i], 24, 1, 1000); /* 24 bit pts in ms */ } put_tag(pb,"FLV"); put_byte(pb,1); put_byte(pb, FLV_HEADER_FLAG_HASAUDIO * flv->hasAudio + FLV_HEADER_FLAG_HASVIDEO * flv->hasVideo); put_be32(pb,9); put_be32(pb,0); for(i=0; i<s->nb_streams; i++){ if(s->streams[i]->codec->codec_tag == 5){ put_byte(pb,8); // message type put_be24(pb,0); // include flags put_be24(pb,0); // time stamp put_be32(pb,0); // reserved put_be32(pb,11); // size flv->reserved=5; } } /* write meta_tag */ put_byte(pb, 18); // tag type META metadata_size_pos= url_ftell(pb); put_be24(pb, 0); // size of data part (sum of all parts below) put_be24(pb, 0); // time stamp put_be32(pb, 0); // reserved /* now data of data_size size */ /* first event name as a string */ put_byte(pb, AMF_DATA_TYPE_STRING); put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ put_byte(pb, AMF_DATA_TYPE_MIXEDARRAY); put_be32(pb, 5*flv->hasVideo + 4*flv->hasAudio + 2); // +2 for duration and file size put_amf_string(pb, "duration"); flv->duration_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write if(flv->hasVideo){ put_amf_string(pb, "width"); put_amf_double(pb, width); put_amf_string(pb, "height"); put_amf_double(pb, height); put_amf_string(pb, "videodatarate"); put_amf_double(pb, s->bit_rate / 1024.0); put_amf_string(pb, "framerate"); put_amf_double(pb, framerate); put_amf_string(pb, "videocodecid"); put_amf_double(pb, videocodecid); } if(flv->hasAudio){ put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, samplerate); put_amf_string(pb, "audiosamplesize"); put_amf_double(pb, samplesize); put_amf_string(pb, "stereo"); put_amf_bool(pb, (channels == 2)); put_amf_string(pb, "audiocodecid"); put_amf_double(pb, audiocodecid); } put_amf_string(pb, "filesize"); flv->filesize_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write put_amf_string(pb, ""); put_byte(pb, AMF_END_OF_OBJECT); /* write total size of tag */ data_size= url_ftell(pb) - metadata_size_pos - 10; url_fseek(pb, metadata_size_pos, SEEK_SET); put_be24(pb, data_size); url_fseek(pb, data_size + 10 - 3, SEEK_CUR); put_be32(pb, data_size + 11); return 0; }
static int aiff_write_header(AVFormatContext *s) { AIFFOutputContext *aiff = s->priv_data; ByteIOContext *pb = &s->pb; AVCodecContext *enc = s->streams[0]->codec; AVExtFloat sample_rate; int coder_len; /* First verify if format is ok */ enc->codec_tag = codec_get_tag(codec_aiff_tags, enc->codec_id); if (!enc->codec_tag) { av_free(aiff); return -1; } coder_len = strlen(enc->codec->name); /* FORM AIFF header */ put_tag(pb, "FORM"); aiff->form = url_ftell(pb); put_be32(pb, 0); /* file length */ put_tag(pb, "AIFC"); /* Version chunk */ put_tag(pb, "FVER"); put_be32(pb, 4); put_be32(pb, 0xA2805140); /* Common chunk */ put_tag(pb, "COMM"); if (coder_len & 1) /* Common chunk is of var size */ put_be32(pb, 23+coder_len); else put_be32(pb, 24+coder_len); put_be16(pb, enc->channels); /* Number of channels */ aiff->frames = url_ftell(pb); put_be32(pb, 0); /* Number of frames */ if (!enc->bits_per_sample) enc->bits_per_sample = (enc->block_align<<3) / enc->channels; put_be16(pb, enc->bits_per_sample); /* Sample size */ sample_rate = av_dbl2ext((double)enc->sample_rate); put_buffer(pb, (uint8_t*)&sample_rate, sizeof(sample_rate)); put_le32(pb, enc->codec_tag); if (coder_len & 1) { put_byte(pb, coder_len); put_buffer(pb, (uint8_t*)enc->codec->name, coder_len); } else { put_byte(pb, coder_len+1); put_buffer(pb, (uint8_t*)enc->codec->name, coder_len); put_byte(pb, 0); } /* Sound data chunk */ put_tag(pb, "SSND"); aiff->ssnd = url_ftell(pb); /* Sound chunk size */ put_be32(pb, 0); /* Sound samples data size */ put_be32(pb, 0); /* Data offset */ put_be32(pb, 0); /* Block-size (block align) */ av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); /* Data is starting here */ put_flush_packet(pb); return 0; }
static int img_write_packet(AVFormatContext *s, AVPacket *pkt) { VideoData *img = s->priv_data; ByteIOContext *pb[3]; char filename[1024]; AVCodecContext *codec= s->streams[ pkt->stream_index ]->codec; int i; if (!img->is_pipe) { if (av_get_frame_filename(filename, sizeof(filename), img->path, img->img_number) < 0 && img->img_number>1) { av_log(s, AV_LOG_ERROR, "Could not get frame filename from pattern\n"); return AVERROR(EIO); } for(i=0; i<3; i++){ if (url_fopen(&pb[i], filename, URL_WRONLY) < 0) { av_log(s, AV_LOG_ERROR, "Could not open file : %s\n",filename); return AVERROR(EIO); } if(codec->codec_id != CODEC_ID_RAWVIDEO) break; filename[ strlen(filename) - 1 ]= 'U' + i; } } else { pb[0] = s->pb; } if(codec->codec_id == CODEC_ID_RAWVIDEO){ int ysize = codec->width * codec->height; put_buffer(pb[0], pkt->data , ysize); put_buffer(pb[1], pkt->data + ysize, (pkt->size - ysize)/2); put_buffer(pb[2], pkt->data + ysize +(pkt->size - ysize)/2, (pkt->size - ysize)/2); put_flush_packet(pb[1]); put_flush_packet(pb[2]); url_fclose(pb[1]); url_fclose(pb[2]); }else{ if(av_str2id(img_tags, s->filename) == CODEC_ID_JPEG2000){ AVStream *st = s->streams[0]; if(st->codec->extradata_size > 8 && AV_RL32(st->codec->extradata+4) == MKTAG('j','p','2','h')){ if(pkt->size < 8 || AV_RL32(pkt->data+4) != MKTAG('j','p','2','c')) goto error; put_be32(pb[0], 12); put_tag (pb[0], "jP "); put_be32(pb[0], 0x0D0A870A); // signature put_be32(pb[0], 20); put_tag (pb[0], "ftyp"); put_tag (pb[0], "jp2 "); put_be32(pb[0], 0); put_tag (pb[0], "jp2 "); put_buffer(pb[0], st->codec->extradata, st->codec->extradata_size); }else if(pkt->size < 8 || (!st->codec->extradata_size && AV_RL32(pkt->data+4) != MKTAG('j','P',' ',' '))){ // signature error: av_log(s, AV_LOG_ERROR, "malformated jpeg2000 codestream\n"); return -1; } } put_buffer(pb[0], pkt->data, pkt->size); } put_flush_packet(pb[0]); if (!img->is_pipe) { url_fclose(pb[0]); } img->img_number++; return 0; }
static void lx_init(const LxBoardDesc *board, MachineState *machine) { #ifdef TARGET_WORDS_BIGENDIAN int be = 1; #else int be = 0; #endif MemoryRegion *system_memory = get_system_memory(); XtensaCPU *cpu = NULL; CPUXtensaState *env = NULL; MemoryRegion *ram, *rom, *system_io; DriveInfo *dinfo; pflash_t *flash = NULL; QemuOpts *machine_opts = qemu_get_machine_opts(); const char *cpu_model = machine->cpu_model; const char *kernel_filename = qemu_opt_get(machine_opts, "kernel"); const char *kernel_cmdline = qemu_opt_get(machine_opts, "append"); const char *dtb_filename = qemu_opt_get(machine_opts, "dtb"); const char *initrd_filename = qemu_opt_get(machine_opts, "initrd"); int n; if (!cpu_model) { cpu_model = XTENSA_DEFAULT_CPU_MODEL; } for (n = 0; n < smp_cpus; n++) { cpu = cpu_xtensa_init(cpu_model); if (cpu == NULL) { error_report("unable to find CPU definition '%s'", cpu_model); exit(EXIT_FAILURE); } env = &cpu->env; env->sregs[PRID] = n; qemu_register_reset(lx60_reset, cpu); /* Need MMU initialized prior to ELF loading, * so that ELF gets loaded into virtual addresses */ cpu_reset(CPU(cpu)); } ram = g_malloc(sizeof(*ram)); memory_region_init_ram(ram, NULL, "lx60.dram", machine->ram_size, &error_fatal); vmstate_register_ram_global(ram); memory_region_add_subregion(system_memory, 0, ram); system_io = g_malloc(sizeof(*system_io)); memory_region_init_io(system_io, NULL, &lx60_io_ops, NULL, "lx60.io", 224 * 1024 * 1024); memory_region_add_subregion(system_memory, 0xf0000000, system_io); lx60_fpga_init(system_io, 0x0d020000); if (nd_table[0].used) { lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000, xtensa_get_extint(env, 1), nd_table); } if (!serial_hds[0]) { serial_hds[0] = qemu_chr_new("serial0", "null", NULL); } serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0), 115200, serial_hds[0], DEVICE_NATIVE_ENDIAN); dinfo = drive_get(IF_PFLASH, 0, 0); if (dinfo) { flash = xtfpga_flash_init(system_io, board, dinfo, be); } /* Use presence of kernel file name as 'boot from SRAM' switch. */ if (kernel_filename) { uint32_t entry_point = env->pc; size_t bp_size = 3 * get_tag_size(0); /* first/last and memory tags */ uint32_t tagptr = 0xfe000000 + board->sram_size; uint32_t cur_tagptr; BpMemInfo memory_location = { .type = tswap32(MEMORY_TYPE_CONVENTIONAL), .start = tswap32(0), .end = tswap32(machine->ram_size), }; uint32_t lowmem_end = machine->ram_size < 0x08000000 ? machine->ram_size : 0x08000000; uint32_t cur_lowmem = QEMU_ALIGN_UP(lowmem_end / 2, 4096); rom = g_malloc(sizeof(*rom)); memory_region_init_ram(rom, NULL, "lx60.sram", board->sram_size, &error_fatal); vmstate_register_ram_global(rom); memory_region_add_subregion(system_memory, 0xfe000000, rom); if (kernel_cmdline) { bp_size += get_tag_size(strlen(kernel_cmdline) + 1); } if (dtb_filename) { bp_size += get_tag_size(sizeof(uint32_t)); } if (initrd_filename) { bp_size += get_tag_size(sizeof(BpMemInfo)); } /* Put kernel bootparameters to the end of that SRAM */ tagptr = (tagptr - bp_size) & ~0xff; cur_tagptr = put_tag(tagptr, BP_TAG_FIRST, 0, NULL); cur_tagptr = put_tag(cur_tagptr, BP_TAG_MEMORY, sizeof(memory_location), &memory_location); if (kernel_cmdline) { cur_tagptr = put_tag(cur_tagptr, BP_TAG_COMMAND_LINE, strlen(kernel_cmdline) + 1, kernel_cmdline); } if (dtb_filename) { int fdt_size; void *fdt = load_device_tree(dtb_filename, &fdt_size); uint32_t dtb_addr = tswap32(cur_lowmem); if (!fdt) { error_report("could not load DTB '%s'", dtb_filename); exit(EXIT_FAILURE); } cpu_physical_memory_write(cur_lowmem, fdt, fdt_size); cur_tagptr = put_tag(cur_tagptr, BP_TAG_FDT, sizeof(dtb_addr), &dtb_addr); cur_lowmem = QEMU_ALIGN_UP(cur_lowmem + fdt_size, 4096); } if (initrd_filename) { BpMemInfo initrd_location = { 0 }; int initrd_size = load_ramdisk(initrd_filename, cur_lowmem, lowmem_end - cur_lowmem); if (initrd_size < 0) { initrd_size = load_image_targphys(initrd_filename, cur_lowmem, lowmem_end - cur_lowmem); } if (initrd_size < 0) { error_report("could not load initrd '%s'", initrd_filename); exit(EXIT_FAILURE); } initrd_location.start = tswap32(cur_lowmem); initrd_location.end = tswap32(cur_lowmem + initrd_size); cur_tagptr = put_tag(cur_tagptr, BP_TAG_INITRD, sizeof(initrd_location), &initrd_location); cur_lowmem = QEMU_ALIGN_UP(cur_lowmem + initrd_size, 4096); } cur_tagptr = put_tag(cur_tagptr, BP_TAG_LAST, 0, NULL); env->regs[2] = tagptr; uint64_t elf_entry; uint64_t elf_lowaddr; int success = load_elf(kernel_filename, translate_phys_addr, cpu, &elf_entry, &elf_lowaddr, NULL, be, EM_XTENSA, 0, 0); if (success > 0) { entry_point = elf_entry; } else { hwaddr ep; int is_linux; success = load_uimage(kernel_filename, &ep, NULL, &is_linux, translate_phys_addr, cpu); if (success > 0 && is_linux) { entry_point = ep; } else { error_report("could not load kernel '%s'", kernel_filename); exit(EXIT_FAILURE); } } if (entry_point != env->pc) { static const uint8_t jx_a0[] = { #ifdef TARGET_WORDS_BIGENDIAN 0x0a, 0, 0, #else 0xa0, 0, 0, #endif }; env->regs[0] = entry_point; cpu_physical_memory_write(env->pc, jx_a0, sizeof(jx_a0)); } } else { if (flash) { MemoryRegion *flash_mr = pflash_cfi01_get_memory(flash); MemoryRegion *flash_io = g_malloc(sizeof(*flash_io)); memory_region_init_alias(flash_io, NULL, "lx60.flash", flash_mr, board->flash_boot_base, board->flash_size - board->flash_boot_base < 0x02000000 ? board->flash_size - board->flash_boot_base : 0x02000000); memory_region_add_subregion(system_memory, 0xfe000000, flash_io); } } }
/* GIF header */ static int gif_image_write_header(ByteIOContext *pb, int width, int height, int loop_count, uint32_t *palette) { int i; unsigned int v; put_tag(pb, "GIF"); put_tag(pb, "89a"); put_le16(pb, width); put_le16(pb, height); put_byte(pb, 0xf7); /* flags: global clut, 256 entries */ put_byte(pb, 0x1f); /* background color index */ put_byte(pb, 0); /* aspect ratio */ /* the global palette */ if (!palette) { put_buffer(pb, (const unsigned char *)gif_clut, 216*3); for(i=0;i<((256-216)*3);i++) put_byte(pb, 0); } else { for(i=0;i<256;i++) { v = palette[i]; put_byte(pb, (v >> 16) & 0xff); put_byte(pb, (v >> 8) & 0xff); put_byte(pb, (v) & 0xff); } } /* update: this is the 'NETSCAPE EXTENSION' that allows for looped animated gif see http://members.aol.com/royalef/gifabout.htm#net-extension byte 1 : 33 (hex 0x21) GIF Extension code byte 2 : 255 (hex 0xFF) Application Extension Label byte 3 : 11 (hex (0x0B) Length of Application Block (eleven bytes of data to follow) bytes 4 to 11 : "NETSCAPE" bytes 12 to 14 : "2.0" byte 15 : 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow) byte 16 : 1 (hex 0x01) bytes 17 to 18 : 0 to 65535, an unsigned integer in lo-hi byte format. This indicate the number of iterations the loop should be executed. bytes 19 : 0 (hex 0x00) a Data Sub-block Terminator */ /* application extension header */ #ifdef GIF_ADD_APP_HEADER if (loop_count >= 0 && loop_count <= 65535) { put_byte(pb, 0x21); put_byte(pb, 0xff); put_byte(pb, 0x0b); put_tag(pb, "NETSCAPE2.0"); // bytes 4 to 14 put_byte(pb, 0x03); // byte 15 put_byte(pb, 0x01); // byte 16 put_le16(pb, (uint16_t)loop_count); put_byte(pb, 0x00); // byte 19 } #endif return 0; }
static int flv_write_header(AVFormatContext *s) { ByteIOContext *pb = &s->pb; FLVContext *flv = s->priv_data; int i, width, height, samplerate; double framerate = 0.0; int metadata_size_pos, data_size; flv->hasAudio = 0; flv->hasVideo = 0; put_tag(pb,"FLV"); put_byte(pb,1); put_byte(pb,0); // delayed write put_be32(pb,9); put_be32(pb,0); for(i=0; i<s->nb_streams; i++){ AVCodecContext *enc = s->streams[i]->codec; if (enc->codec_type == CODEC_TYPE_VIDEO) { width = enc->width; height = enc->height; if (s->streams[i]->r_frame_rate.den && s->streams[i]->r_frame_rate.num) { framerate = av_q2d(s->streams[i]->r_frame_rate); } else { framerate = 1/av_q2d(s->streams[i]->codec->time_base); } flv->hasVideo=1; } else { flv->hasAudio=1; samplerate = enc->sample_rate; } av_set_pts_info(s->streams[i], 24, 1, 1000); /* 24 bit pts in ms */ if(enc->codec_tag == 5){ put_byte(pb,8); // message type put_be24(pb,0); // include flags put_be24(pb,0); // time stamp put_be32(pb,0); // reserved put_be32(pb,11); // size flv->reserved=5; } if(enc->codec_type == CODEC_TYPE_AUDIO && get_audio_flags(enc)<0) return -1; } /* write meta_tag */ put_byte(pb, 18); // tag type META metadata_size_pos= url_ftell(pb); put_be24(pb, 0); // size of data part (sum of all parts below) put_be24(pb, 0); // time stamp put_be32(pb, 0); // reserved /* now data of data_size size */ /* first event name as a string */ put_byte(pb, AMF_STRING); // 1 byte put_amf_string(pb, "onMetaData"); // 12 bytes /* mixed array (hash) with size and string/type/data tuples */ put_byte(pb, AMF_MIXED_ARRAY); put_be32(pb, 4*flv->hasVideo + flv->hasAudio + 2); // +2 for duration and file size put_amf_string(pb, "duration"); flv->duration_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write if(flv->hasVideo){ put_amf_string(pb, "width"); put_amf_double(pb, width); put_amf_string(pb, "height"); put_amf_double(pb, height); put_amf_string(pb, "videodatarate"); put_amf_double(pb, s->bit_rate / 1024.0); put_amf_string(pb, "framerate"); put_amf_double(pb, framerate); } if(flv->hasAudio){ put_amf_string(pb, "audiosamplerate"); put_amf_double(pb, samplerate); } put_amf_string(pb, "filesize"); flv->filesize_offset= url_ftell(pb); put_amf_double(pb, 0); // delayed write put_amf_string(pb, ""); put_byte(pb, 9); // end marker 1 byte /* write total size of tag */ data_size= url_ftell(pb) - metadata_size_pos - 10; url_fseek(pb, metadata_size_pos, SEEK_SET); put_be24(pb, data_size); url_fseek(pb, data_size + 10 - 3, SEEK_CUR); put_be32(pb, data_size + 11); return 0; }