static bstr read_file(struct mp_log *log, const char *filename) { FILE *f = fopen(filename, "rb"); if (!f) { mp_verbose(log, "Can't open config file: %s\n", mp_strerror(errno)); return (bstr){0}; } char *data = talloc_array(NULL, char, 0); size_t size = 0; while (1) { size_t left = talloc_get_size(data) - size; if (!left) { MP_TARRAY_GROW(NULL, data, size + 1); continue; } size_t s = fread(data + size, 1, left, f); if (!s) { if (ferror(f)) mp_err(log, "Error reading config file.\n"); fclose(f); MP_TARRAY_APPEND(NULL, data, size, 0); return (bstr){data, size - 1}; } size += s; } assert(0); }
/* * Skip to (probable) next cluster (MATROSKA_ID_CLUSTER) element start position. */ int ebml_resync_cluster(struct mp_log *log, stream_t *s) { int64_t pos = stream_tell(s); uint32_t last_4_bytes = 0; mp_err(log, "Corrupt file detected. " "Trying to resync starting from position %"PRId64"...\n", pos); while (!s->eof) { // Assumes MATROSKA_ID_CLUSTER is 4 bytes, with no 0 bytes. if (last_4_bytes == MATROSKA_ID_CLUSTER) { mp_err(log, "Cluster found at %"PRId64".\n", pos - 4); stream_seek(s, pos - 4); return 0; } last_4_bytes = (last_4_bytes << 8) | stream_read_char(s); pos++; } return -1; }
// kv is in the format as by OPT_KEYVALUELIST(): kv[0]=key0, kv[1]=val0, ... // Set these options on given avobj (using av_opt_set..., meaning avobj must // point to a struct that has AVClass as first member). // Options which fail to set (error or not found) are printed to log. // Returns: >=0 success, <0 failed to set an option int mp_set_avopts(struct mp_log *log, void *avobj, char **kv) { int success = 0; for (int n = 0; kv && kv[n * 2]; n++) { char *k = kv[n * 2 + 0]; char *v = kv[n * 2 + 1]; resolve_positional_arg(avobj, &k); int r = av_opt_set(avobj, k, v, AV_OPT_SEARCH_CHILDREN); if (r == AVERROR_OPTION_NOT_FOUND) { mp_err(log, "AVOption '%s' not found.\n", k); success = -1; } else if (r < 0) { char errstr[80]; av_strerror(r, errstr, sizeof(errstr)); mp_err(log, "Could not set AVOption %s='%s' (%s)\n", k, v, errstr); success = -1; } } return success; }
static tvi_handle_t *tv_begin(tv_param_t* tv_param, struct mp_log *log) { int i; tvi_handle_t* h; if(tv_param->driver && !strcmp(tv_param->driver,"help")){ mp_info(log, "Available drivers:\n"); for(i=0;tvi_driver_list[i];i++){ mp_info(log, " %s\t%s",tvi_driver_list[i]->short_name,tvi_driver_list[i]->name); if(tvi_driver_list[i]->comment) mp_info(log, " (%s)",tvi_driver_list[i]->comment); mp_info(log, "\n"); } return NULL; } for(i=0;tvi_driver_list[i];i++){ if (!tv_param->driver || !strcmp(tvi_driver_list[i]->short_name, tv_param->driver)){ h=tvi_driver_list[i]->tvi_init(log, tv_param); //Requested driver initialization failed if (!h && tv_param->driver) return NULL; //Driver initialization failed during autodetection process. if (!h) continue; h->tv_param=tv_param; MP_INFO(h, "Selected driver: %s\n name: %s\n author: %s\n comment: %s\n", tvi_driver_list[i]->short_name, tvi_driver_list[i]->name, tvi_driver_list[i]->author, tvi_driver_list[i]->comment?tvi_driver_list[i]->comment:""); tv_param->driver=strdup(tvi_driver_list[i]->short_name); return h; } } if(tv_param->driver) mp_err(log, "No such driver: %s\n", tv_param->driver); else mp_err(log, "TV driver autodetection failed.\n"); return NULL; }
static const char *libguess_guess(struct mp_log *log, bstr buf, const char *language) { if (!language || !language[0] || strcmp(language, "help") == 0) { mp_err(log, "libguess needs a language: " "japanese taiwanese chinese korean russian arabic turkish " "greek hebrew polish baltic\n"); return NULL; } return libguess_determine_encoding(buf.start, buf.len, language); }
int dvb_get_tuner_type(int fe_fd, struct mp_log *log) { struct dvb_frontend_info fe_info; int res; res = ioctl(fe_fd, FE_GET_INFO, &fe_info); if(res < 0) { mp_err(log, "FE_GET_INFO error: %d, FD: %d\n\n", errno, fe_fd); return 0; } switch(fe_info.type) { case FE_OFDM: mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-T\n"); return TUNER_TER; case FE_QPSK: mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-S\n"); return TUNER_SAT; case FE_QAM: mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-C\n"); return TUNER_CBL; #ifdef DVB_ATSC case FE_ATSC: mp_verbose(log, "TUNER TYPE SEEMS TO BE DVB-ATSC\n"); return TUNER_ATSC; #endif default: mp_err(log, "UNKNOWN TUNER TYPE\n"); return 0; } }
struct playlist *playlist_parse_file(const char *file, struct mpv_global *global) { struct mp_log *log = mp_log_new(NULL, global->log, "!playlist_parser"); mp_verbose(log, "Parsing playlist file %s...\n", file); struct playlist *ret = NULL; stream_t *stream = stream_open(file, global); if(!stream) { mp_err(log, "Error while opening playlist file %s\n", file); talloc_free(log); return NULL; } struct demuxer *pl_demux = demux_open(stream, "playlist", NULL, global); if (pl_demux && pl_demux->playlist) { ret = talloc_zero(NULL, struct playlist); playlist_transfer_entries(ret, pl_demux->playlist); }
/* * Skip the current element. * end: the end of the parent element or -1 (for robust error handling) */ int ebml_read_skip(struct mp_log *log, int64_t end, stream_t *s) { uint64_t len; int64_t pos = stream_tell(s); len = ebml_read_length(s); if (len == EBML_UINT_INVALID) goto invalid; int64_t pos2 = stream_tell(s); if (len >= INT64_MAX - pos2 || (end > 0 && pos2 + len > end)) goto invalid; if (!stream_skip(s, len)) goto invalid; return 0; invalid: mp_err(log, "Invalid EBML length at position %"PRId64"\n", pos); stream_seek(s, pos); return 1; }
// Use iconv to convert buf to UTF-8. // Returns buf.start==NULL on error. Returns buf if cp is NULL, or if there is // obviously no conversion required (e.g. if cp is "UTF-8"). // Returns a newly allocated buffer if conversion is done and succeeds. The // buffer will be terminated with 0 for convenience (the terminating 0 is not // included in the returned length). // Free the returned buffer with talloc_free(). // buf: input data // cp: iconv codepage (or NULL) // flags: combination of MP_ICONV_* flags // returns: buf (no conversion), .start==NULL (error), or allocated buffer bstr mp_iconv_to_utf8(struct mp_log *log, bstr buf, const char *cp, int flags) { #if HAVE_ICONV if (!cp || !cp[0] || mp_charset_is_utf8(cp)) return buf; if (strcasecmp(cp, "ASCII") == 0) return buf; if (strcasecmp(cp, "UTF-8-BROKEN") == 0) return bstr_sanitize_utf8_latin1(NULL, buf); iconv_t icdsc; if ((icdsc = iconv_open("UTF-8", cp)) == (iconv_t) (-1)) { if (flags & MP_ICONV_VERBOSE) mp_err(log, "Error opening iconv with codepage '%s'\n", cp); goto failure; } size_t size = buf.len; size_t osize = size; size_t ileft = size; size_t oleft = size - 1; char *outbuf = talloc_size(NULL, osize); char *ip = buf.start; char *op = outbuf; while (1) { int clear = 0; size_t rc; if (ileft) rc = iconv(icdsc, &ip, &ileft, &op, &oleft); else { clear = 1; // clear the conversion state and leave rc = iconv(icdsc, NULL, NULL, &op, &oleft); } if (rc == (size_t) (-1)) { if (errno == E2BIG) { size_t offset = op - outbuf; outbuf = talloc_realloc_size(NULL, outbuf, osize + size); op = outbuf + offset; osize += size; oleft += size; } else { if (errno == EINVAL && (flags & MP_ICONV_ALLOW_CUTOFF)) { // This is intended for cases where the input buffer is cut // at a random byte position. If this happens in the middle // of the buffer, it should still be an error. We say it's // fine if the error is within 10 bytes of the end. if (ileft <= 10) break; } if (flags & MP_ICONV_VERBOSE) { mp_err(log, "Error recoding text with codepage '%s'\n", cp); } talloc_free(outbuf); iconv_close(icdsc); goto failure; } } else if (clear) break; } iconv_close(icdsc); outbuf[osize - oleft - 1] = 0; return (bstr){outbuf, osize - oleft - 1}; #endif failure: return (bstr){0}; }
struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd, int crtc_id, int connector_id, int osd_plane_id, int video_plane_id) { drmModePlaneRes *plane_res = NULL; drmModeRes *res = NULL; struct drm_object *plane = NULL; struct drm_atomic_context *ctx; int crtc_index = -1; int layercount = -1; int primary_id = 0; int overlay_id = 0; uint64_t value; res = drmModeGetResources(fd); if (!res) { mp_err(log, "Cannot retrieve DRM resources: %s\n", mp_strerror(errno)); goto fail; } plane_res = drmModeGetPlaneResources(fd); if (!plane_res) { mp_err(log, "Cannot retrieve plane ressources: %s\n", mp_strerror(errno)); goto fail; } ctx = talloc_zero(NULL, struct drm_atomic_context); if (!ctx) { mp_err(log, "Out of memory\n"); goto fail; } ctx->fd = fd; ctx->crtc = drm_object_create(log, ctx->fd, crtc_id, DRM_MODE_OBJECT_CRTC); if (!ctx->crtc) { mp_err(log, "Failed to create CRTC object\n"); goto fail; } for (int i = 0; i < res->count_crtcs; i++) { if (res->crtcs[i] == crtc_id) { crtc_index = i; break; } } for (int i = 0; i < res->count_connectors; i++) { drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[i]); if (connector) { if (connector->connector_id == connector_id) ctx->connector = drm_object_create(log, ctx->fd, connector->connector_id, DRM_MODE_OBJECT_CONNECTOR); drmModeFreeConnector(connector); if (ctx->connector) break; } } for (unsigned int j = 0; j < plane_res->count_planes; j++) { drmModePlane *drmplane = drmModeGetPlane(ctx->fd, plane_res->planes[j]); const uint32_t possible_crtcs = drmplane->possible_crtcs; const uint32_t plane_id = drmplane->plane_id; drmModeFreePlane(drmplane); drmplane = NULL; if (possible_crtcs & (1 << crtc_index)) { plane = drm_object_create(log, ctx->fd, plane_id, DRM_MODE_OBJECT_PLANE); if (!plane) { mp_err(log, "Failed to create Plane object from plane ID %d\n", plane_id); goto fail; } if (drm_object_get_property(plane, "TYPE", &value) == -EINVAL) { mp_err(log, "Unable to retrieve type property from plane %d\n", j); goto fail; } if (value != DRM_PLANE_TYPE_CURSOR) { // Skip cursor planes layercount++; if ((!primary_id) && (value == DRM_PLANE_TYPE_PRIMARY)) primary_id = plane_id; if ((!overlay_id) && (value == DRM_PLANE_TYPE_OVERLAY)) overlay_id = plane_id; if (layercount == osd_plane_id) { ctx->osd_plane = plane; continue; } if (layercount == video_plane_id) { ctx->video_plane = plane; continue; } } drm_object_free(plane); plane = NULL; } } // default OSD plane to primary if unspecified if (!ctx->osd_plane) { if (primary_id) { mp_verbose(log, "Using default plane %d for OSD\n", primary_id); ctx->osd_plane = drm_object_create(log, ctx->fd, primary_id, DRM_MODE_OBJECT_PLANE); } else { mp_err(log, "Failed to find OSD plane with id=%d\n", osd_plane_id); goto fail; } } else { mp_verbose(log, "Found OSD plane with ID %d\n", ctx->osd_plane->id); } // default video plane to overlay if unspecified if (!ctx->video_plane) { if (overlay_id) { mp_verbose(log, "Using default plane %d for video\n", overlay_id); ctx->video_plane = drm_object_create(log, ctx->fd, overlay_id, DRM_MODE_OBJECT_PLANE); } else { mp_verbose(log, "Failed to find video plane with id=%d. drmprime-drm hwdec interop will not work\n", video_plane_id); } } else { mp_verbose(log, "Found video plane with ID %d\n", ctx->video_plane->id); } drmModeFreePlaneResources(plane_res); drmModeFreeResources(res); return ctx; fail: if (res) drmModeFreeResources(res); if (plane_res) drmModeFreePlaneResources(plane_res); if (plane) drm_object_free(plane); return NULL; }
dvb_state_t *dvb_get_state(stream_t *stream) { if (global_dvb_state != NULL) { return global_dvb_state; } struct mp_log *log = stream->log; struct mpv_global *global = stream->global; dvb_priv_t *priv = stream->priv; int type, size; char filename[30], *name; dvb_channels_list *list; dvb_card_config_t *cards = NULL, *tmp; dvb_state_t *state = NULL; state = malloc(sizeof(dvb_state_t)); if (state == NULL) return NULL; state->count = 0; state->switching_channel = false; state->stream_used = true; state->cards = NULL; state->fe_fd = state->dvr_fd = -1; for (int i = 0; i < MAX_CARDS; i++) { snprintf(filename, sizeof(filename), "/dev/dvb/adapter%d/frontend0", i); int fd = open(filename, O_RDONLY | O_NONBLOCK | O_CLOEXEC); if (fd < 0) { mp_verbose(log, "DVB_CONFIG, can't open device %s, skipping\n", filename); continue; } mp_verbose(log, "Opened device %s, FD: %d\n", filename, fd); int* tuner_types = NULL; int num_tuner_types = dvb_get_tuner_types(fd, log, &tuner_types); close(fd); mp_verbose(log, "Frontend device %s offers %d supported delivery systems.\n", filename, num_tuner_types); for (int num_tuner_type=0; num_tuner_type<num_tuner_types; num_tuner_type++) { type = tuner_types[num_tuner_type]; if (type != TUNER_SAT && type != TUNER_TER && type != TUNER_CBL && type != TUNER_ATSC) { mp_verbose(log, "DVB_CONFIG, can't detect tuner type of " "card %d, skipping\n", i); continue; } void *talloc_ctx = talloc_new(NULL); char *conf_file = NULL; if (priv->cfg_file && priv->cfg_file[0]) conf_file = priv->cfg_file; else { switch (type) { case TUNER_TER: conf_file = mp_find_config_file(talloc_ctx, global, "channels.conf.ter"); break; case TUNER_CBL: conf_file = mp_find_config_file(talloc_ctx, global, "channels.conf.cbl"); break; case TUNER_SAT: conf_file = mp_find_config_file(talloc_ctx, global, "channels.conf.sat"); break; case TUNER_ATSC: conf_file = mp_find_config_file(talloc_ctx, global, "channels.conf.atsc"); break; } if (conf_file) { mp_verbose(log, "Ignoring other channels.conf files.\n"); } else { conf_file = mp_find_config_file(talloc_ctx, global, "channels.conf"); } } list = dvb_get_channels(log, priv->cfg_full_transponder, conf_file, type); talloc_free(talloc_ctx); if (list == NULL) continue; size = sizeof(dvb_card_config_t) * (state->count + 1); tmp = realloc(state->cards, size); if (tmp == NULL) { mp_err(log, "DVB_CONFIG, can't realloc %d bytes, skipping\n", size); free(list); continue; } cards = tmp; name = malloc(20); if (name == NULL) { mp_err(log, "DVB_CONFIG, can't realloc 20 bytes, skipping\n"); free(list); free(tmp); continue; } state->cards = cards; state->cards[state->count].devno = i; state->cards[state->count].list = list; state->cards[state->count].type = type; snprintf(name, 20, "DVB-%c card n. %d", type == TUNER_TER ? 'T' : (type == TUNER_CBL ? 'C' : 'S'), state->count + 1); state->cards[state->count].name = name; state->count++; } talloc_free(tuner_types); } if (state->count == 0) { free(state); state = NULL; } global_dvb_state = state; return state; }
struct mp_image *convert_image(struct mp_image *image, int destfmt, struct mp_log *log) { int d_w, d_h; mp_image_params_get_dsize(&image->params, &d_w, &d_h); struct mp_image_params p = { .imgfmt = destfmt, .w = d_w, .h = d_h, .p_w = 1, .p_h = 1, }; mp_image_params_guess_csp(&p); // If RGB, just assume everything is correct. if (p.color.space != MP_CSP_RGB) { // Currently, assume what FFmpeg's jpg encoder needs. // Of course this works only for non-HDR (no HDR support in libswscale). p.color.levels = MP_CSP_LEVELS_PC; p.color.space = MP_CSP_BT_601; p.chroma_location = MP_CHROMA_CENTER; mp_image_params_guess_csp(&p); } if (mp_image_params_equal(&p, &image->params)) return mp_image_new_ref(image); struct mp_image *dst = mp_image_alloc(p.imgfmt, p.w, p.h); if (!dst) { mp_err(log, "Out of memory.\n"); return NULL; } mp_image_copy_attributes(dst, image); dst->params = p; if (mp_image_swscale(dst, image, mp_sws_hq_flags) < 0) { mp_err(log, "Error when converting image.\n"); talloc_free(dst); return NULL; } return dst; } bool write_image(struct mp_image *image, const struct image_writer_opts *opts, const char *filename, struct mp_log *log) { struct image_writer_opts defs = image_writer_opts_defaults; if (!opts) opts = &defs; struct image_writer_ctx ctx = { log, opts, image->fmt }; bool (*write)(struct image_writer_ctx *, mp_image_t *, FILE *) = write_lavc; int destfmt = 0; #if HAVE_JPEG if (opts->format == AV_CODEC_ID_MJPEG) { write = write_jpeg; destfmt = IMGFMT_RGB24; } #endif if (!destfmt) destfmt = get_target_format(&ctx); struct mp_image *dst = convert_image(image, destfmt, log); if (!dst) return false; FILE *fp = fopen(filename, "wb"); bool success = false; if (fp == NULL) { mp_err(log, "Error opening '%s' for writing!\n", filename); } else { success = write(&ctx, dst, fp); success = !fclose(fp) && success; if (!success) mp_err(log, "Error writing file '%s'!\n", filename); } talloc_free(dst); return success; } void dump_png(struct mp_image *image, const char *filename, struct mp_log *log) { struct image_writer_opts opts = image_writer_opts_defaults; opts.format = AV_CODEC_ID_PNG; write_image(image, &opts, filename, log); }