func: static int open_output_file(OptionsContext *o, const char *filename)
  
  {
  
      AVFormatContext *oc;
  
      int i, j, err;
  
      AVOutputFormat *file_oformat;
  
      OutputFile *of;
  
      OutputStream *ost;
  
      InputStream  *ist;
  
      AVDictionary *unused_opts = NULL;
  
      AVDictionaryEntry *e = NULL;
  
  
  
      if (configure_complex_filters() < 0) {
  
          av_log(NULL, AV_LOG_FATAL, "Error configuring filters.\n");
  
          exit_program(1);
  
      }
  
  
  
      if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) {
  
          o->stop_time = INT64_MAX;
  
          av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n");
  
      }
  
  
  
      if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) {
  
          int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time;
  
          if (o->stop_time <= start_time) {
  
              av_log(NULL, AV_LOG_WARNING, "-to value smaller than -ss; ignoring -to.\n");
  
              o->stop_time = INT64_MAX;
  
          } else {
  
              o->recording_time = o->stop_time - start_time;
  
          }
  
      }
  
  
  
      GROW_ARRAY(output_files, nb_output_files);
  
      of = av_mallocz(sizeof(*of));
  
      if (!of)
  
          exit_program(1);
  
      output_files[nb_output_files - 1] = of;
  
  
  
      of->ost_index      = nb_output_streams;
  
      of->recording_time = o->recording_time;
  
      of->start_time     = o->start_time;
  
      of->limit_filesize = o->limit_filesize;
  
      of->shortest       = o->shortest;
  
      av_dict_copy(&of->opts, o->g->format_opts, 0);
  
  
  
      if (!strcmp(filename, "-"))
  
          filename = "pipe:";
  
  
  
      err = avformat_alloc_output_context2(&oc, NULL, o->format, filename);
  
      if (!oc) {
  
          print_error(filename, err);
  
          exit_program(1);
  
      }
  
  
  
      of->ctx = oc;
  
      if (o->recording_time != INT64_MAX)
  
          oc->duration = o->recording_time;
  
  
  
      file_oformat= oc->oformat;
  
      oc->interrupt_callback = int_cb;
  
  
  
      /* create streams for all unlabeled output pads */
  
      for (i = 0; i < nb_filtergraphs; i++) {
  
          FilterGraph *fg = filtergraphs[i];
  
          for (j = 0; j < fg->nb_outputs; j++) {
  
              OutputFilter *ofilter = fg->outputs[j];
  
  
  
              if (!ofilter->out_tmp || ofilter->out_tmp->name)
  
                  continue;
  
  
  
              switch (avfilter_pad_get_type(ofilter->out_tmp->filter_ctx->output_pads,
  
                                            ofilter->out_tmp->pad_idx)) {
  
              case AVMEDIA_TYPE_VIDEO:    o->video_disable    = 1; break;
  
              case AVMEDIA_TYPE_AUDIO:    o->audio_disable    = 1; break;
  
              case AVMEDIA_TYPE_SUBTITLE: o->subtitle_disable = 1; break;
  
              }
  
              init_output_filter(ofilter, o, oc);
  
          }
  
      }
  
  
  
      /* ffserver seeking with date=... needs a date reference */
  
      if (!strcmp(file_oformat->name, "ffm") &&
  
          av_strstart(filename, "http:", NULL)) {
  
          int err = parse_option(o, "metadata", "creation_time=now", options);
  
          if (err < 0) {
  
              print_error(filename, err);
  
              exit_program(1);
  
          }
  
      }
  
  
  
      if (!strcmp(file_oformat->name, "ffm") && !override_ffserver &&
  
          av_strstart(filename, "http:", NULL)) {
  
          int j;
  
          /* special case for files sent to ffserver: we get the stream
  
             parameters from ffserver */
  
          int err = read_ffserver_streams(o, oc, filename);
  
          if (err < 0) {
  
              print_error(filename, err);
  
              exit_program(1);
  
          }
  
          for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) {
  
              ost = output_streams[j];
  
              for (i = 0; i < nb_input_streams; i++) {
  
                  ist = input_streams[i];
  
                  if(ist->st->codec->codec_type == ost->st->codec->codec_type){
  
                      ost->sync_ist= ist;
  
                      ost->source_index= i;
  
                      if(ost->st->codec->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull");
  
                      if(ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null");
  
                      ist->discard = 0;
  
                      ist->st->discard = AVDISCARD_NONE;
  
                      break;
  
                  }
  
              }
  
              if(!ost->sync_ist){
  
                  av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codec->codec_type));
  
                  exit_program(1);
  
              }
  
          }
  
      } else if (!o->nb_stream_maps) {
  
          char *subtitle_codec_name = NULL;
  
          /* pick the "best" stream of each type */
  
  
  
          /* video: highest resolution */
  
          if (!o->video_disable && oc->oformat->video_codec != AV_CODEC_ID_NONE) {
  
              int area = 0, idx = -1;
  
              int qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0);
  
              for (i = 0; i < nb_input_streams; i++) {
  
                  int new_area;
  
                  ist = input_streams[i];
  
                  new_area = ist->st->codec->width * ist->st->codec->height;
  
                  if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
  
                      new_area = 1;
  
                  if (ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
  
                      new_area > area) {
  
                      if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC))
  
                          continue;
  
                      area = new_area;
  
                      idx = i;
  
                  }
  
              }
  
              if (idx >= 0)
  
                  new_video_stream(o, oc, idx);
  
          }
  
  
  
          /* audio: most channels */
  
          if (!o->audio_disable && oc->oformat->audio_codec != AV_CODEC_ID_NONE) {
  
              int channels = 0, idx = -1;
  
              for (i = 0; i < nb_input_streams; i++) {
  
                  ist = input_streams[i];
  
                  if (ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
  
                      ist->st->codec->channels > channels) {
  
                      channels = ist->st->codec->channels;
  
                      idx = i;
  
                  }
  
              }
  
              if (idx >= 0)
  
                  new_audio_stream(o, oc, idx);
  
          }
  
  
  
          /* subtitles: pick first */
  
          MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, oc, "s");
  
          if (!o->subtitle_disable && (oc->oformat->subtitle_codec != AV_CODEC_ID_NONE || subtitle_codec_name)) {
  
              for (i = 0; i < nb_input_streams; i++)
  
                  if (input_streams[i]->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
  
                      new_subtitle_stream(o, oc, i);
  
                      break;
  
                  }
  
          }
  
          /* do something with data? */
  
      } else {
  
          for (i = 0; i < o->nb_stream_maps; i++) {
  
              StreamMap *map = &o->stream_maps[i];
  
  
  
              if (map->disabled)
  
                  continue;
  
  
  
              if (map->linklabel) {
  
                  FilterGraph *fg;
  
                  OutputFilter *ofilter = NULL;
  
                  int j, k;
  
  
  
                  for (j = 0; j < nb_filtergraphs; j++) {
  
                      fg = filtergraphs[j];
  
                      for (k = 0; k < fg->nb_outputs; k++) {
  
                          AVFilterInOut *out = fg->outputs[k]->out_tmp;
  
                          if (out && !strcmp(out->name, map->linklabel)) {
  
                              ofilter = fg->outputs[k];
  
                              goto loop_end;
  
                          }
  
                      }
  
                  }
  
  loop_end:
  
                  if (!ofilter) {
  
                      av_log(NULL, AV_LOG_FATAL, "Output with label '%s' does not exist "
  
                             "in any defined filter graph, or was already used elsewhere.\n", map->linklabel);
  
                      exit_program(1);
  
                  }
  
                  init_output_filter(ofilter, o, oc);
  
              } else {
  
                  int src_idx = input_files[map->file_index]->ist_index + map->stream_index;
  
  
  
                  ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index];
  
                  if(o->subtitle_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
  
                      continue;
  
                  if(o->   audio_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
  
                      continue;
  
                  if(o->   video_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  
                      continue;
  
                  if(o->    data_disable && ist->st->codec->codec_type == AVMEDIA_TYPE_DATA)
  
                      continue;
  
  
  
                  switch (ist->st->codec->codec_type) {
  
                  case AVMEDIA_TYPE_VIDEO:      ost = new_video_stream     (o, oc, src_idx); break;
  
                  case AVMEDIA_TYPE_AUDIO:      ost = new_audio_stream     (o, oc, src_idx); break;
  
                  case AVMEDIA_TYPE_SUBTITLE:   ost = new_subtitle_stream  (o, oc, src_idx); break;
  
                  case AVMEDIA_TYPE_DATA:       ost = new_data_stream      (o, oc, src_idx); break;
  
                  case AVMEDIA_TYPE_ATTACHMENT: ost = new_attachment_stream(o, oc, src_idx); break;
  
                  default:
  
                      av_log(NULL, AV_LOG_FATAL, "Cannot map stream #%d:%d - unsupported type.\n",
  
                             map->file_index, map->stream_index);
  
                      exit_program(1);
  
                  }
  
              }
  
          }
  
      }
  
  
  
      /* handle attached files */
  
      for (i = 0; i < o->nb_attachments; i++) {
  
          AVIOContext *pb;
  
          uint8_t *attachment;
  
          const char *p;
  
          int64_t len;
  
  
  
          if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) {
  
              av_log(NULL, AV_LOG_FATAL, "Could not open attachment file %s.\n",
  
                     o->attachments[i]);
  
              exit_program(1);
  
          }
  
          if ((len = avio_size(pb)) <= 0) {
  
              av_log(NULL, AV_LOG_FATAL, "Could not get size of the attachment %s.\n",
  
                     o->attachments[i]);
  
              exit_program(1);
  
          }
  
          if (!(attachment = av_malloc(len))) {
  
              av_log(NULL, AV_LOG_FATAL, "Attachment %s too large to fit into memory.\n",
  
                     o->attachments[i]);
  
              exit_program(1);
  
          }
  
          avio_read(pb, attachment, len);
  
  
  
          ost = new_attachment_stream(o, oc, -1);
  
          ost->stream_copy               = 0;
  
          ost->attachment_filename       = o->attachments[i];
  
          ost->finished                  = 1;
  
          ost->st->codec->extradata      = attachment;
  
          ost->st->codec->extradata_size = len;
  
  
  
          p = strrchr(o->attachments[i], '/');
  
          av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE);
  
          avio_close(pb);
  
      }
  
  
  
      for (i = nb_output_streams - oc->nb_streams; i < nb_output_streams; i++) { //for all streams of this output file
  
          AVDictionaryEntry *e;
  
          ost = output_streams[i];
  
  
  
          if ((ost->stream_copy || ost->attachment_filename)
  
              && (e = av_dict_get(o->g->codec_opts, "flags", NULL, AV_DICT_IGNORE_SUFFIX))
  
              && (!e->key[5] || check_stream_specifier(oc, ost->st, e->key+6)))
  
              if (av_opt_set(ost->st->codec, "flags", e->value, 0) < 0)
  
                  exit_program(1);
  
      }
  
  
  
      /* check if all codec options have been used */
  
      unused_opts = strip_specifiers(o->g->codec_opts);
  
      for (i = of->ost_index; i < nb_output_streams; i++) {
  
          e = NULL;
  
          while ((e = av_dict_get(output_streams[i]->opts, "", e,
  
                                  AV_DICT_IGNORE_SUFFIX)))
  
              av_dict_set(&unused_opts, e->key, NULL, 0);
  
      }
  
  
  
      e = NULL;
  
      while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
  
          const AVClass *class = avcodec_get_class();
  
          const AVOption *option = av_opt_find(&class, e->key, NULL, 0,
  
                                               AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ);
  
          if (!option)
  
              continue;
  
          if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) {
  
              av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for "
  
                     "output file #%d (%s) is not an encoding option.\n", e->key,
  
                     option->help ? option->help : "", nb_output_files - 1,
  
                     filename);
  
              exit_program(1);
  
          }
  
  
  
          // gop_timecode is injected by generic code but not always used
  
          if (!strcmp(e->key, "gop_timecode"))
  
              continue;
  
  
  
          av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for "
  
                 "output file #%d (%s) has not been used for any stream. The most "
  
                 "likely reason is either wrong type (e.g. a video option with "
  
                 "no video streams) or that it is a private option of some encoder "
  
                 "which was not actually used for any stream.\n", e->key,
  
                 option->help ? option->help : "", nb_output_files - 1, filename);
  
      }
  
      av_dict_free(&unused_opts);
  
  
  
      /* check filename in case of an image number is expected */
  
      if (oc->oformat->flags & AVFMT_NEEDNUMBER) {
  
          if (!av_filename_number_test(oc->filename)) {
  
              print_error(oc->filename, AVERROR(EINVAL));
  
              exit_program(1);
  
          }
  
      }
  
  
  
      if (!(oc->oformat->flags & AVFMT_NOFILE)) {
  
          /* test if it already exists to avoid losing precious files */
  
          assert_file_overwrite(filename);
  
  
  
          /* open the file */
  
          if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE,
  
                                &oc->interrupt_callback,
  
                                &of->opts)) < 0) {
  
              print_error(filename, err);
  
              exit_program(1);
  
          }
  
      } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename))
  
          assert_file_overwrite(filename);
  
  
  
      if (o->mux_preload) {
  
          uint8_t buf[64];
  
          snprintf(buf, sizeof(buf), "%d", (int)(o->mux_preload*AV_TIME_BASE));
  
          av_dict_set(&of->opts, "preload", buf, 0);
  
      }
  
      oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE);
  
  
  
      /* copy metadata */
  
      for (i = 0; i < o->nb_metadata_map; i++) {
  
          char *p;
  
          int in_file_index = strtol(o->metadata_map[i].u.str, &p, 0);
  
  
  
          if (in_file_index >= nb_input_files) {
  
              av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d while processing metadata maps\n", in_file_index);
  
              exit_program(1);
  
          }
  
          copy_metadata(o->metadata_map[i].specifier, *p ? p + 1 : p, oc,
  
                        in_file_index >= 0 ?
  
                        input_files[in_file_index]->ctx : NULL, o);
  
      }
  
  
  
      /* copy chapters */
  
      if (o->chapters_input_file >= nb_input_files) {
  
          if (o->chapters_input_file == INT_MAX) {
  
              /* copy chapters from the first input file that has them*/
  
              o->chapters_input_file = -1;
  
              for (i = 0; i < nb_input_files; i++)
  
                  if (input_files[i]->ctx->nb_chapters) {
  
                      o->chapters_input_file = i;
  
                      break;
  
                  }
  
          } else {
  
              av_log(NULL, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n",
  
                     o->chapters_input_file);
  
              exit_program(1);
  
          }
  
      }
  
      if (o->chapters_input_file >= 0)
  
          copy_chapters(input_files[o->chapters_input_file], of,
  
                        !o->metadata_chapters_manual);
  
  
  
      /* copy global metadata by default */
  
      if (!o->metadata_global_manual && nb_input_files){
  
          av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata,
  
                       AV_DICT_DONT_OVERWRITE);
  
          if(o->recording_time != INT64_MAX)
  
              av_dict_set(&oc->metadata, "duration", NULL, 0);
  
          av_dict_set(&oc->metadata, "creation_time", NULL, 0);
  
      }
  
      if (!o->metadata_streams_manual)
  
          for (i = of->ost_index; i < nb_output_streams; i++) {
  
              InputStream *ist;
  
              if (output_streams[i]->source_index < 0)         /* this is true e.g. for attached files */
  
                  continue;
  
              ist = input_streams[output_streams[i]->source_index];
  
              av_dict_copy(&output_streams[i]->st->metadata, ist->st->metadata, AV_DICT_DONT_OVERWRITE);
  
          }
  
  
  
      /* process manually set metadata */
  
      for (i = 0; i < o->nb_metadata; i++) {
  
          AVDictionary **m;
  
          char type, *val;
  
          const char *stream_spec;
  
          int index = 0, j, ret = 0;
  
  
  
          val = strchr(o->metadata[i].u.str, '=');
  
          if (!val) {
  
              av_log(NULL, AV_LOG_FATAL, "No '=' character in metadata string %s.\n",
  
                     o->metadata[i].u.str);
  
              exit_program(1);
  
          }
  
          *val++ = 0;
  
  
  
          parse_meta_type(o->metadata[i].specifier, &type, &index, &stream_spec);
  
          if (type == 's') {
  
              for (j = 0; j < oc->nb_streams; j++) {
  
                  if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) {
  
                      av_dict_set(&oc->streams[j]->metadata, o->metadata[i].u.str, *val ? val : NULL, 0);
  
                  } else if (ret < 0)
  
                      exit_program(1);
  
              }
  
          }
  
          else {
  
              switch (type) {
  
              case 'g':
  
                  m = &oc->metadata;
  
                  break;
  
              case 'c':
  
                  if (index < 0 || index >= oc->nb_chapters) {
  
                      av_log(NULL, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index);
  
                      exit_program(1);
  
                  }
  
                  m = &oc->chapters[index]->metadata;
  
                  break;
  
              default:
  
                  av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
  
                  exit_program(1);
  
              }
  
              av_dict_set(m, o->metadata[i].u.str, *val ? val : NULL, 0);
  
          }
  
      }
  
  
  
      return 0;
  
  }
  