bool FFmpegBaseWriter::open(const char* filename, int fourcc, double fps, int width, int height, bool iscolor, bool need_encode) { static const struct AVCodecTag *table[] = { avformat_get_riff_video_tags(), 0 }; enum AVCodecID id = av_codec_get_id(table, fourcc); media_stream_params_t params; params.height_video = height; params.width_video = width; params.video_fps = fps; params.codec_id = id; stream_ = alloc_video_stream(filename, ¶ms, need_encode); channels_ = iscolor ? 3 : 1; return true; }
static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, ReportList *reports) { /* Handle to the output file */ AVFormatContext* of; AVOutputFormat* fmt; char name[256]; const char ** exts; ffmpeg_type = rd->ffcodecdata.type; ffmpeg_codec = rd->ffcodecdata.codec; ffmpeg_audio_codec = rd->ffcodecdata.audio_codec; ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate; ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate; ffmpeg_gop_size = rd->ffcodecdata.gop_size; ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT; do_init_ffmpeg(); /* Determine the correct filename */ filepath_ffmpeg(name, rd); fprintf(stderr, "Starting output to %s(ffmpeg)...\n" " Using type=%d, codec=%d, audio_codec=%d,\n" " video_bitrate=%d, audio_bitrate=%d,\n" " gop_size=%d, autosplit=%d\n" " render width=%d, render height=%d\n", name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec, ffmpeg_video_bitrate, ffmpeg_audio_bitrate, ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty); exts = get_file_extensions(ffmpeg_type); if (!exts) { BKE_report(reports, RPT_ERROR, "No valid formats found."); return 0; } fmt = av_guess_format(NULL, exts[0], NULL); if (!fmt) { BKE_report(reports, RPT_ERROR, "No valid formats found."); return 0; } of = avformat_alloc_context(); if (!of) { BKE_report(reports, RPT_ERROR, "Error opening output file"); return 0; } of->oformat = fmt; of->packet_size= rd->ffcodecdata.mux_packet_size; if (ffmpeg_audio_codec != CODEC_ID_NONE) { of->mux_rate = rd->ffcodecdata.mux_rate; } else { of->mux_rate = 0; } of->preload = (int)(0.5*AV_TIME_BASE); of->max_delay = (int)(0.7*AV_TIME_BASE); fmt->audio_codec = ffmpeg_audio_codec; BLI_snprintf(of->filename, sizeof(of->filename), "%s", name); /* set the codec to the user's selection */ switch(ffmpeg_type) { case FFMPEG_AVI: case FFMPEG_MOV: case FFMPEG_MKV: fmt->video_codec = ffmpeg_codec; break; case FFMPEG_OGG: fmt->video_codec = CODEC_ID_THEORA; break; case FFMPEG_DV: fmt->video_codec = CODEC_ID_DVVIDEO; break; case FFMPEG_MPEG1: fmt->video_codec = CODEC_ID_MPEG1VIDEO; break; case FFMPEG_MPEG2: fmt->video_codec = CODEC_ID_MPEG2VIDEO; break; case FFMPEG_H264: fmt->video_codec = CODEC_ID_H264; break; case FFMPEG_XVID: fmt->video_codec = CODEC_ID_MPEG4; break; case FFMPEG_FLV: fmt->video_codec = CODEC_ID_FLV1; break; case FFMPEG_MP3: fmt->audio_codec = CODEC_ID_MP3; case FFMPEG_WAV: fmt->video_codec = CODEC_ID_NONE; break; case FFMPEG_MPEG4: default: fmt->video_codec = CODEC_ID_MPEG4; break; } if (fmt->video_codec == CODEC_ID_DVVIDEO) { if (rectx != 720) { BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!"); return 0; } if (rd->frs_sec != 25 && recty != 480) { BKE_report(reports, RPT_ERROR, "Render height has to be 480 pixels for DV-NTSC!"); return 0; } if (rd->frs_sec == 25 && recty != 576) { BKE_report(reports, RPT_ERROR, "Render height has to be 576 pixels for DV-PAL!"); return 0; } } if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) { BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!"); return 0; } } if (fmt->video_codec != CODEC_ID_NONE) { video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty); printf("alloc video stream %p\n", video_stream); if (!video_stream) { BKE_report(reports, RPT_ERROR, "Error initializing video stream."); return 0; } } if (ffmpeg_audio_codec != CODEC_ID_NONE) { audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of); if (!audio_stream) { BKE_report(reports, RPT_ERROR, "Error initializing audio stream."); return 0; } } if (av_set_parameters(of, NULL) < 0) { BKE_report(reports, RPT_ERROR, "Error setting output parameters."); return 0; } if (!(fmt->flags & AVFMT_NOFILE)) { if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) { BKE_report(reports, RPT_ERROR, "Could not open file for writing."); return 0; } } if (av_write_header(of) < 0) { BKE_report(reports, RPT_ERROR, "Could not initialize streams. Probably unsupported codec combination."); return 0; } outfile = of; av_dump_format(of, 0, name, 1); return 1; }
static int start_ffmpeg_impl(FFMpegContext *context, struct RenderData *rd, int rectx, int recty, const char *suffix, ReportList *reports) { /* Handle to the output file */ AVFormatContext *of; AVOutputFormat *fmt; AVDictionary *opts = NULL; char name[256], error[1024]; const char **exts; context->ffmpeg_type = rd->ffcodecdata.type; context->ffmpeg_codec = rd->ffcodecdata.codec; context->ffmpeg_audio_codec = rd->ffcodecdata.audio_codec; context->ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate; context->ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate; context->ffmpeg_gop_size = rd->ffcodecdata.gop_size; context->ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT; /* Determine the correct filename */ ffmpeg_filepath_get(context, name, rd, context->ffmpeg_preview, suffix); PRINT("Starting output to %s(ffmpeg)...\n" " Using type=%d, codec=%d, audio_codec=%d,\n" " video_bitrate=%d, audio_bitrate=%d,\n" " gop_size=%d, autosplit=%d\n" " render width=%d, render height=%d\n", name, context->ffmpeg_type, context->ffmpeg_codec, context->ffmpeg_audio_codec, context->ffmpeg_video_bitrate, context->ffmpeg_audio_bitrate, context->ffmpeg_gop_size, context->ffmpeg_autosplit, rectx, recty); exts = get_file_extensions(context->ffmpeg_type); if (!exts) { BKE_report(reports, RPT_ERROR, "No valid formats found"); return 0; } fmt = av_guess_format(NULL, exts[0], NULL); if (!fmt) { BKE_report(reports, RPT_ERROR, "No valid formats found"); return 0; } of = avformat_alloc_context(); if (!of) { BKE_report(reports, RPT_ERROR, "Error opening output file"); return 0; } of->oformat = fmt; of->packet_size = rd->ffcodecdata.mux_packet_size; if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) { ffmpeg_dict_set_int(&opts, "muxrate", rd->ffcodecdata.mux_rate); } else { av_dict_set(&opts, "muxrate", "0", 0); } ffmpeg_dict_set_int(&opts, "preload", (int)(0.5 * AV_TIME_BASE)); of->max_delay = (int)(0.7 * AV_TIME_BASE); fmt->audio_codec = context->ffmpeg_audio_codec; BLI_strncpy(of->filename, name, sizeof(of->filename)); /* set the codec to the user's selection */ switch (context->ffmpeg_type) { case FFMPEG_AVI: case FFMPEG_MOV: case FFMPEG_MKV: fmt->video_codec = context->ffmpeg_codec; break; case FFMPEG_OGG: fmt->video_codec = AV_CODEC_ID_THEORA; break; case FFMPEG_DV: fmt->video_codec = AV_CODEC_ID_DVVIDEO; break; case FFMPEG_MPEG1: fmt->video_codec = AV_CODEC_ID_MPEG1VIDEO; break; case FFMPEG_MPEG2: fmt->video_codec = AV_CODEC_ID_MPEG2VIDEO; break; case FFMPEG_H264: fmt->video_codec = AV_CODEC_ID_H264; break; case FFMPEG_XVID: fmt->video_codec = AV_CODEC_ID_MPEG4; break; case FFMPEG_FLV: fmt->video_codec = AV_CODEC_ID_FLV1; break; case FFMPEG_MPEG4: default: fmt->video_codec = context->ffmpeg_codec; break; } if (fmt->video_codec == AV_CODEC_ID_DVVIDEO) { if (rectx != 720) { BKE_report(reports, RPT_ERROR, "Render width has to be 720 pixels for DV!"); return 0; } if (rd->frs_sec != 25 && recty != 480) { BKE_report(reports, RPT_ERROR, "Render height has to be 480 pixels for DV-NTSC!"); return 0; } if (rd->frs_sec == 25 && recty != 576) { BKE_report(reports, RPT_ERROR, "Render height has to be 576 pixels for DV-PAL!"); return 0; } } if (context->ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = AV_CODEC_ID_PCM_S16LE; if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) { BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!"); av_dict_free(&opts); return 0; } } if (fmt->video_codec != AV_CODEC_ID_NONE) { context->video_stream = alloc_video_stream(context, rd, fmt->video_codec, of, rectx, recty, error, sizeof(error)); PRINT("alloc video stream %p\n", context->video_stream); if (!context->video_stream) { if (error[0]) BKE_report(reports, RPT_ERROR, error); else BKE_report(reports, RPT_ERROR, "Error initializing video stream"); av_dict_free(&opts); return 0; } } if (context->ffmpeg_audio_codec != AV_CODEC_ID_NONE) { context->audio_stream = alloc_audio_stream(context, rd, fmt->audio_codec, of, error, sizeof(error)); if (!context->audio_stream) { if (error[0]) BKE_report(reports, RPT_ERROR, error); else BKE_report(reports, RPT_ERROR, "Error initializing audio stream"); av_dict_free(&opts); return 0; } } if (!(fmt->flags & AVFMT_NOFILE)) { if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) { BKE_report(reports, RPT_ERROR, "Could not open file for writing"); av_dict_free(&opts); return 0; } } if (avformat_write_header(of, NULL) < 0) { BKE_report(reports, RPT_ERROR, "Could not initialize streams, probably unsupported codec combination"); av_dict_free(&opts); avio_close(of->pb); return 0; } context->outfile = of; av_dump_format(of, 0, name, 1); av_dict_free(&opts); return 1; }
int main(int argc, char *argv[]) { av_register_all(); media_stream_params_t params; params.height_video = height; params.width_video = width; params.video_fps = fps; params.bit_stream = bit_rate; params.codec_id = AV_CODEC_ID_H264; media_stream_t* ostream = alloc_video_stream(outfilename, ¶ms, 0); if(!ostream){ return EXIT_FAILURE; } char errbuf[PCAP_ERRBUF_SIZE]; pcap_t* pcap = pcap_open_offline_with_tstamp_precision(infilename, PCAP_TSTAMP_PRECISION_NANO, errbuf); if (!pcap) { fprintf(stderr, "error reading pcap file: %s\n", errbuf); free_video_stream(ostream); return EXIT_FAILURE; } struct pcap_pkthdr header; const u_char *packet; while ((packet = pcap_next(pcap, &header)) != NULL) { packet += sizeof(struct vgem_hdr); bpf_u_int32 packet_len = header.caplen - sizeof(struct vgem_hdr); if (packet_len < sizeof(struct ether_header)) { pcap_close(pcap); free_video_stream(ostream); return EXIT_FAILURE; } struct ether_header* ethernet_header = (struct ether_header*)packet; uint16_t ht = ntohs(ethernet_header->ether_type); if (ht != ETHERTYPE_IP) { continue; } /* Skip over the Ethernet header. (14)*/ packet += sizeof(struct ether_header); packet_len -= sizeof(struct ether_header); if (packet_len < sizeof(struct ip)) { pcap_close(pcap); free_video_stream(ostream); return EXIT_FAILURE; } struct iphdr* ip = (struct iphdr*) packet; if (!(ip->protocol != IPPROTO_UDP || ip->protocol != IPPROTO_TCP)) { continue; } unsigned int IP_header_length = ip->ihl * 4; /* ip_hl is in 4-byte words */ if (packet_len < IP_header_length) { /* didn't capture the full IP header including options */ pcap_close(pcap); free_video_stream(ostream); return EXIT_FAILURE; } packet += IP_header_length; packet_len -= IP_header_length; if (ip->protocol == IPPROTO_UDP) { if (packet_len < sizeof(struct udphdr)) { pcap_close(pcap); free_video_stream(ostream); return EXIT_FAILURE; } packet += sizeof(struct udphdr); packet_len -= sizeof(struct udphdr); struct rtp_hdr* rtp = (struct rtp_hdr*)packet; if (packet_len < sizeof(struct rtp_hdr)) { pcap_close(pcap); free_video_stream(ostream); return EXIT_FAILURE; } // rtp payload packet += sizeof(struct rtp_hdr); packet_len -= sizeof(struct rtp_hdr); if (packet_len <= 2) { continue; } uint8_t nal = packet[0]; uint8_t fragment_type = (nal & 0x1F); if (fragment_type >= 1 && fragment_type <= 23) { uint8_t* nal_data = NULL; size_t size_nal = make_nal_frame_header(packet, packet_len, nal_header, sizeof(nal_header), &nal_data); media_stream_write_video_frame(ostream, nal_data, size_nal); free(nal_data); } else if(fragment_type == 24) { packet++; packet_len--; // first we are going to figure out the total size.... { int total_length= 0; uint8_t* dst = NULL; int pass; for(pass = 0; pass < 2; pass++) { const uint8_t* src = packet; int src_len = packet_len; do { uint16_t nal_size = AV_RB16(src); // this going to be a problem if unaligned (can it be?) // consume the length of the aggregate... src += 2; src_len -= 2; if (nal_size <= src_len) { if(pass==0) { // counting... total_length+= sizeof(nal_header)+nal_size; } else { // copying assert(dst); memcpy(dst, nal_header, sizeof(nal_header)); dst += sizeof(nal_header); memcpy(dst, src, nal_size); dst += nal_size; } } else { av_log(NULL, AV_LOG_ERROR, "nal size exceeds length: %d %d\n", nal_size, src_len); } // eat what we handled... src += nal_size; src_len -= nal_size; if (src_len < 0) av_log(NULL, AV_LOG_ERROR, "Consumed more bytes than we got! (%d)\n", src_len); } while (src_len > 2); // because there could be rtp padding.. if (pass == 0) { dst = (uint8_t*)calloc(total_length, sizeof(uint8_t)); } else { } } } } else if (fragment_type == 28 || fragment_type == 29) { packet++; packet_len--; uint8_t fu_indicator = nal; uint8_t fu_header = *packet; // read the fu_header. uint8_t start_bit = fu_header >> 7; uint8_t end_bit = (fu_header & 0x40) >> 6; uint8_t nal_type = (fu_header & 0x1f); uint8_t reconstructed_nal = fu_indicator & (0xe0); // the original nal forbidden bit and NRI are stored in this packet's nal; reconstructed_nal |= nal_type; packet++; packet_len--; if (fragment_type == 29) { packet = packet + 2; packet_len -= 2; } CHECK(packet_len > 0); if (start_bit) { size_t size_nal = sizeof(nal_header) + sizeof(nal) + packet_len; uint8_t* nal_data = (uint8_t*)calloc(size_nal, sizeof(uint8_t)); memcpy(nal_data, nal_header, sizeof(nal_header)); nal_data[sizeof(nal_header)]= reconstructed_nal; memcpy(nal_data + sizeof(nal_header) + sizeof(nal), packet, packet_len); media_stream_write_video_frame(ostream, nal_data, size_nal); free(nal_data); } else { media_stream_write_video_frame(ostream, packet, packet_len); } } else { NOTREACHED(); } // http://stackoverflow.com/questions/3493742/problem-to-decode-h264-video-over-rtp-with-ffmpeg-libavcodec // http://stackoverflow.com/questions/1957427/detect-mpeg4-h264-i-frame-idr-in-rtp-stream } else if (ip->protocol == IPPROTO_TCP) {